Options

Game Dev - Unreal 4.13 Out Now!

15455575960100

Posts

  • Options
    MNC DoverMNC Dover Full-time Voice Actor Kirkland, WARegistered User regular
    Forgot to mention, I re-uploaded my Star Wars game for Star Wars day today.

    http://cloudpop.itch.io/starwarsday

    That was cute. Do you have a formula in place so that the incoming shots aren't impossible to block?

    Need a voice actor? Hire me at bengrayVO.com
    Legends of Runeterra: MNCdover #moc
    Switch ID: MNC Dover SW-1154-3107-1051
    Steam ID
    Twitch Page
  • Options
    HallowedFaithHallowedFaith Call me Cloud. Registered User regular
    MNC Dover wrote: »
    Forgot to mention, I re-uploaded my Star Wars game for Star Wars day today.

    http://cloudpop.itch.io/starwarsday

    That was cute. Do you have a formula in place so that the incoming shots aren't impossible to block?

    There is a timing system that takes into consideration the max amount of time it takes to do a 180 to ensure that it helps keep things fair, but it's not 100% spot on.

    I'm making video games. DesignBy.Cloud
  • Options
    ZekZek Registered User regular
    edited May 2015
    Zek wrote: »
    Still tinkering with Unity 2D, got a basic Zelda-style dungeon in place with randomly generated rooms. For now I figure I'll just treat it as a blank canvas project, adding content/polish in my free time and figuring out what feels fun:

    https://www.youtube.com/watch?v=8hGhopb3zp8

    This looks great, how did you end up implementing the randomly generated rooms?

    For the rooms themselves I cheated a bit and made two sets of prefabs - one for all the possible outer wall exit combinations (i.e. "NESW Room"), and one for all the possible room contents (i.e. "Mid Block 4 Enemies Contents"). Then I attached scripts to each of those to store the relevant flags and wrote a LevelGenerator script to assemble them into a level. I got a bit fancy by building it to also support bigger rooms that occupy multiple "MapNodes" - see spoiler for my data model:
    public class Level : MonoBehaviour {
    
      public List<Room> rooms;
      public MapNode[,] map;
      public Room startingRoom;
      [HideInInspector]
      public Room currentRoom;
      [HideInInspector]
      public bool changingRooms;
    }
    
    public class Room : MonoBehaviour {
    
      public List<MapNode> mapNodes;
      public RoomContents contents;
      
      [HideInInspector]
      public bool isActive;
    
      [HideInInspector]
      public MapNode bottomLeftNode;
    
      [HideInInspector]
      public List<Enemy> enemies;
    }
    
    [System.Serializable]
    public class MapNode : MonoBehaviour {
      
      public static int UNIT_HEIGHT = 10;
      public static int UNIT_WIDTH = 16;
    
      // coords within the Room
      public int x = 0;
      public int y = 0;
      public List<RoomExit> exits;
      
      [HideInInspector]
      public Room room;
    
      // coords within the Level's map
      [HideInInspector]
      public int mapX;
      [HideInInspector]
      public int mapY;
    }
    
    public class RoomExit : MonoBehaviour {
    
      public Direction direction;
      
      [HideInInspector]
      public MapNode mapNode;
    }
    
    public class RoomContents : MonoBehaviour {
    
      public PlayerSpawner playerSpawner;
      public List<Enemy> possibleEnemies;
      public List<EnemySpawner> enemySpawners;
    }
    

    The generator script works by setting up an empty grid of MapNodes and plopping a starting room in the middle of it. Then it keeps count of the number of rooms it wants to create per level, and starts creating rooms to satisfy all the exits from the starting room, being careful not to add a room that will either close off all the exits prematurely or create too many total exits. Each room it creates is added to a queue which will then be handled in turn, i.e. a breadth-first traversal.

    Here's the generator script so far, though it's not well commented:
    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;
    
    public class LevelGenerator : MonoBehaviour {
    
      public static int MAP_HEIGHT = 7;
      public static int MAP_WIDTH = 7;
      public static int STARTING_X = 3;
      public static int STARTING_Y = 3;
      public static int ROOMS_PER_LEVEL = 15;
      // The number of exits that are allowed to go unused if the level gen traps itself in a corner
      public static int UNUSED_EXIT_TOLERANCE = 3;
    
      public List<Room> possibleRooms;
      public List<RoomContents> possibleRoomContents;
      public List<RoomContents> possibleSpawnRoomContents;
    
      private Level level;
      private MapNode[,] map;
      private int exitsRemaining;
      private int openExits;
    
      public Level GenerateLevel(Level level) {
        this.level = Instantiate(level);
        level.changingRooms = false;
        this.map = new MapNode[MAP_WIDTH + 1, MAP_HEIGHT + 1];
        level.map = map;
        exitsRemaining = ROOMS_PER_LEVEL - 1;
        openExits = 0;
    
        RoomAnchor startingRoomAnchor = AddRoomAt(STARTING_X, STARTING_Y, true);
        Room startingRoom = startingRoomAnchor.room;
        level.startingRoom = startingRoom;
        level.currentRoom = startingRoom;
    
        Queue<RoomAnchor> roomAnchors = new Queue<RoomAnchor>();
        roomAnchors.Enqueue(startingRoomAnchor);
        while (roomAnchors.Count > 0) {
          var roomAnchor = roomAnchors.Dequeue();
          foreach (var node in roomAnchor.room.mapNodes) {
            int x = roomAnchor.x + node.x;
            int y = roomAnchor.y + node.y;
            if (node.HasNorthExit()) {
              RoomAnchor newRoomAnchor = AddRoomAt(x, y + 1, false);
              if (newRoomAnchor != null) {
                roomAnchors.Enqueue(newRoomAnchor);
              }
            }
            if (node.HasEastExit()) {
              RoomAnchor newRoomAnchor = AddRoomAt(x + 1, y, false);
              if (newRoomAnchor != null) {
                roomAnchors.Enqueue(newRoomAnchor);
              }
            }
            if (node.HasSouthExit()) {
              RoomAnchor newRoomAnchor = AddRoomAt(x, y - 1, false);
              if (newRoomAnchor != null) {
                roomAnchors.Enqueue(newRoomAnchor);
              }
            }
            if (node.HasWestExit()) {
              RoomAnchor newRoomAnchor = AddRoomAt(x - 1, y, false);
              if (newRoomAnchor != null) {
                roomAnchors.Enqueue(newRoomAnchor);
              }
            }
          }
        }
        level.startingRoom.SetActive(true);
    
        return level;
      }
    
      RoomAnchor AddRoomAt(int x, int y, bool forSpawn) {
        RoomAnchor roomAnchor = ChooseRoom(x, y);
        if (roomAnchor == null) {
          return null;
        }
        roomAnchor.room = CreateRoom(level, roomAnchor.room, roomAnchor.x, roomAnchor.y, forSpawn);
    
        int newOpenExits = GetNumOpenExits(roomAnchor);
        int newClosedExits = roomAnchor.room.NumExits() - newOpenExits;
        exitsRemaining -= newOpenExits;
        openExits += (roomAnchor.room.NumExits() - newClosedExits * 2);
        return roomAnchor;
      }
    
      RoomAnchor ChooseRoom(int x, int y) {
        if (map[x, y] != null) {
          return null;
        }
        List<RoomAnchor> eligibleRoomAnchors = new List<RoomAnchor>();
        foreach (var room in possibleRooms) {
          eligibleRoomAnchors.AddRange(GetValidRoomAnchors(room, x, y));
        }
        if (eligibleRoomAnchors.Count > 0) {
          return eligibleRoomAnchors[Utils.RandomIndex(0, eligibleRoomAnchors.Count)];
        } else {
          return null;
        }
      }
    
      List<RoomAnchor> GetValidRoomAnchors(Room room, int x, int y) {
        List<RoomAnchor> roomAnchors = new List<RoomAnchor>();
        foreach (var anchorNode in room.mapNodes) {
          // Find where the bottom left of this room would be if this node were the anchor
          int bottomLeftX = x - anchorNode.x;
          int bottomLeftY = y - anchorNode.y;
          if (bottomLeftX < 0 || bottomLeftY < 0) {
            continue;
          }
          RoomAnchor roomAnchor = new RoomAnchor(room, bottomLeftX, bottomLeftY);
          if (IsRoomAnchorValid(roomAnchor)) {
            roomAnchors.Add(roomAnchor);
          }
        }
        return roomAnchors;
      }
    
      bool IsRoomAnchorValid(RoomAnchor roomAnchor) {
        foreach (var node in roomAnchor.room.mapNodes) {
          if (!IsNodeValid(node, roomAnchor.x + node.x, roomAnchor.y + node.y)) {
            return false;
          }
        }
    
        int newOpenExits = GetNumOpenExits(roomAnchor);
        if (newOpenExits > exitsRemaining) {
          return false;
        }
        if (exitsRemaining > UNUSED_EXIT_TOLERANCE && newOpenExits == 0 &&
            roomAnchor.room.NumExits() >= openExits) {
          // This room is going to use up the last of the exits - don't let that happen unless we're at
          // the threshold
          return false;
        }
    
        return true;
      }
    
      int GetNumOpenExits(RoomAnchor roomAnchor) {
        int openExits = 0;
    
        foreach (var node in roomAnchor.room.mapNodes) {
          int x = roomAnchor.x + node.x;
          int y = roomAnchor.y + node.y;
    
          if (node.HasNorthExit() && map[x, y + 1] == null) {
            openExits++;
          }
          if (node.HasEastExit() && map[x + 1, y] == null) {
            openExits++;
          }
          if (node.HasSouthExit() && map[x, y - 1] == null) {
            openExits++;
          }
          if (node.HasWestExit() && map[x - 1, y] == null) {
            openExits++;
          }
        }
    
        return openExits;
      }
    
      bool IsNodeValid(MapNode node, int x, int y) {
        if (x > MAP_WIDTH || y > MAP_HEIGHT || map[x, y] != null) {
          return false;
        }
    
        if (x == 0 && node.HasWestExit() ||
            x == MAP_WIDTH - 1 && node.HasEastExit() ||
            y == 0 && node.HasSouthExit() ||
            y == MAP_HEIGHT - 1 && node.HasNorthExit()) {
          return false;
        }
    
        MapNode westNode = x > 0 ? map[x - 1, y] : null;
        MapNode eastNode = x < MAP_WIDTH - 1 ? map[x + 1, y] : null;
        MapNode southNode = y > 0 ? map[x, y - 1] : null;
        MapNode northNode = y < MAP_HEIGHT - 1 ? map[x, y + 1] : null;
    
        if (westNode != null && westNode.HasEastExit() && !node.HasWestExit()) {
          return false;
        }
        if (westNode != null && !westNode.HasEastExit() && node.HasWestExit()) {
          return false;
        }
        if (eastNode != null && eastNode.HasWestExit() && !node.HasEastExit()) {
          return false;
        }
        if (eastNode != null && !eastNode.HasWestExit() && node.HasEastExit()) {
          return false;
        }
        if (southNode != null && southNode.HasNorthExit() && !node.HasSouthExit()) {
          return false;
        }
        if (southNode != null && !southNode.HasNorthExit() && node.HasSouthExit()) {
          return false;
        }
        if (northNode != null && northNode.HasSouthExit() && !node.HasNorthExit()) {
          return false;
        }
        if (northNode != null && !northNode.HasSouthExit() && node.HasNorthExit()) {
          return false;
        }
    
        return true;
      }
    
      Room CreateRoom(Level level, Room room, int x, int y, bool forSpawn) {
        Room newRoom = Instantiate(room);
        RoomContents newContents;
        if (forSpawn) {
          newContents = Instantiate(
              possibleSpawnRoomContents[Utils.RandomIndex(0, possibleSpawnRoomContents.Count)]);
        } else {
          newContents = Instantiate(
              possibleRoomContents[Utils.RandomIndex(0, possibleRoomContents.Count)]);
        }
        
        newRoom.contents = newContents;
        newContents.transform.parent = newRoom.transform;
        UpdateRoomPosition(newRoom, x, y);
        //newRoom.SetActive(false);
        level.rooms.Add(newRoom);
    
        foreach (var node in newRoom.mapNodes) {
          node.mapX = x + node.x;
          node.mapY = y + node.y;
          map[node.mapX, node.mapY] = node;
        }
    
        return newRoom;
      }
    
      void UpdateRoomPosition(Room room, int x, int y) {
        float xPos = x * MapNode.UNIT_WIDTH;
        float yPos = y * MapNode.UNIT_HEIGHT;
        room.transform.position = new Vector2(xPos, yPos);
      }
    
      /**
       * Wrapper object to store a theoretical room together with the x/y coords of its bottom left
       * MapNode. This is used to check each possible placement of a large room to see where it can fit
       * on the map.
       */
      public class RoomAnchor {
        public Room room;
        public int x;
        public int y;
    
        public RoomAnchor(Room room, int x, int y) {
          this.room = room;
          this.x = x;
          this.y = y;
        }
      }
    }
    

    Zek on
  • Options
    KashaarKashaar Low OrbitRegistered User regular
    It looks like I might be getting some freelance work using Unity, and all I'm really familiar with is Unreal. Specifically, this would be VFX stuff - so I'm wondering, does anyone of you guys have any personal recommendations for good Unity 5 FX tutorials before I strike out into the wild on my own? :-)

    Indie Dev Blog | Twitter | Steam
    Unreal Engine 4 Developers Community.

    I'm working on a cute little video game! Here's a link for you.
  • Options
    rembrandtqeinsteinrembrandtqeinstein Registered User regular
    Zek wrote: »
    Zek wrote: »
    Still tinkering with Unity 2D, got a basic Zelda-style dungeon in place with randomly generated rooms. For now I figure I'll just treat it as a blank canvas project, adding content/polish in my free time and figuring out what feels fun:

    https://www.youtube.com/watch?v=8hGhopb3zp8

    This looks great, how did you end up implementing the randomly generated rooms?

    For the rooms themselves I cheated a bit and made two sets of prefabs - one for all the possible outer wall exit combinations (i.e. "NESW Room"), and one for all the possible room contents (i.e. "Mid Block 4 Enemies Contents"). Then I attached scripts to each of those to store the relevant flags and wrote a LevelGenerator script to assemble them into a level. I got a bit fancy by building it to also support bigger rooms that occupy multiple "MapNodes" - see spoiler for my data model:
    public class Level : MonoBehaviour {
    
      public List<Room> rooms;
      public MapNode[,] map;
      public Room startingRoom;
      [HideInInspector]
      public Room currentRoom;
      [HideInInspector]
      public bool changingRooms;
    }
    
    public class Room : MonoBehaviour {
    
      public List<MapNode> mapNodes;
      public RoomContents contents;
      
      [HideInInspector]
      public bool isActive;
    
      [HideInInspector]
      public MapNode bottomLeftNode;
    
      [HideInInspector]
      public List<Enemy> enemies;
    }
    
    [System.Serializable]
    public class MapNode : MonoBehaviour {
      
      public static int UNIT_HEIGHT = 10;
      public static int UNIT_WIDTH = 16;
    
      // coords within the Room
      public int x = 0;
      public int y = 0;
      public List<RoomExit> exits;
      
      [HideInInspector]
      public Room room;
    
      // coords within the Level's map
      [HideInInspector]
      public int mapX;
      [HideInInspector]
      public int mapY;
    }
    
    public class RoomExit : MonoBehaviour {
    
      public Direction direction;
      
      [HideInInspector]
      public MapNode mapNode;
    }
    
    public class RoomContents : MonoBehaviour {
    
      public PlayerSpawner playerSpawner;
      public List<Enemy> possibleEnemies;
      public List<EnemySpawner> enemySpawners;
    }
    

    The generator script works by setting up an empty grid of MapNodes and plopping a starting room in the middle of it. Then it keeps count of the number of rooms it wants to create per level, and starts creating rooms to satisfy all the exits from the starting room, being careful not to add a room that will either close off all the exits prematurely or create too many total exits. Each room it creates is added to a queue which will then be handled in turn, i.e. a breadth-first traversal.

    Here's the generator script so far, though it's not well commented:
    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;
    
    public class LevelGenerator : MonoBehaviour {
    
      public static int MAP_HEIGHT = 7;
      public static int MAP_WIDTH = 7;
      public static int STARTING_X = 3;
      public static int STARTING_Y = 3;
      public static int ROOMS_PER_LEVEL = 15;
      // The number of exits that are allowed to go unused if the level gen traps itself in a corner
      public static int UNUSED_EXIT_TOLERANCE = 3;
    
      public List<Room> possibleRooms;
      public List<RoomContents> possibleRoomContents;
      public List<RoomContents> possibleSpawnRoomContents;
    
      private Level level;
      private MapNode[,] map;
      private int exitsRemaining;
      private int openExits;
    
      public Level GenerateLevel(Level level) {
        this.level = Instantiate(level);
        level.changingRooms = false;
        this.map = new MapNode[MAP_WIDTH + 1, MAP_HEIGHT + 1];
        level.map = map;
        exitsRemaining = ROOMS_PER_LEVEL - 1;
        openExits = 0;
    
        RoomAnchor startingRoomAnchor = AddRoomAt(STARTING_X, STARTING_Y, true);
        Room startingRoom = startingRoomAnchor.room;
        level.startingRoom = startingRoom;
        level.currentRoom = startingRoom;
    
        Queue<RoomAnchor> roomAnchors = new Queue<RoomAnchor>();
        roomAnchors.Enqueue(startingRoomAnchor);
        while (roomAnchors.Count > 0) {
          var roomAnchor = roomAnchors.Dequeue();
          foreach (var node in roomAnchor.room.mapNodes) {
            int x = roomAnchor.x + node.x;
            int y = roomAnchor.y + node.y;
            if (node.HasNorthExit()) {
              RoomAnchor newRoomAnchor = AddRoomAt(x, y + 1, false);
              if (newRoomAnchor != null) {
                roomAnchors.Enqueue(newRoomAnchor);
              }
            }
            if (node.HasEastExit()) {
              RoomAnchor newRoomAnchor = AddRoomAt(x + 1, y, false);
              if (newRoomAnchor != null) {
                roomAnchors.Enqueue(newRoomAnchor);
              }
            }
            if (node.HasSouthExit()) {
              RoomAnchor newRoomAnchor = AddRoomAt(x, y - 1, false);
              if (newRoomAnchor != null) {
                roomAnchors.Enqueue(newRoomAnchor);
              }
            }
            if (node.HasWestExit()) {
              RoomAnchor newRoomAnchor = AddRoomAt(x - 1, y, false);
              if (newRoomAnchor != null) {
                roomAnchors.Enqueue(newRoomAnchor);
              }
            }
          }
        }
        level.startingRoom.SetActive(true);
    
        return level;
      }
    
      RoomAnchor AddRoomAt(int x, int y, bool forSpawn) {
        RoomAnchor roomAnchor = ChooseRoom(x, y);
        if (roomAnchor == null) {
          return null;
        }
        roomAnchor.room = CreateRoom(level, roomAnchor.room, roomAnchor.x, roomAnchor.y, forSpawn);
    
        int newOpenExits = GetNumOpenExits(roomAnchor);
        int newClosedExits = roomAnchor.room.NumExits() - newOpenExits;
        exitsRemaining -= newOpenExits;
        openExits += (roomAnchor.room.NumExits() - newClosedExits * 2);
        return roomAnchor;
      }
    
      RoomAnchor ChooseRoom(int x, int y) {
        if (map[x, y] != null) {
          return null;
        }
        List<RoomAnchor> eligibleRoomAnchors = new List<RoomAnchor>();
        foreach (var room in possibleRooms) {
          eligibleRoomAnchors.AddRange(GetValidRoomAnchors(room, x, y));
        }
        if (eligibleRoomAnchors.Count > 0) {
          return eligibleRoomAnchors[Utils.RandomIndex(0, eligibleRoomAnchors.Count)];
        } else {
          return null;
        }
      }
    
      List<RoomAnchor> GetValidRoomAnchors(Room room, int x, int y) {
        List<RoomAnchor> roomAnchors = new List<RoomAnchor>();
        foreach (var anchorNode in room.mapNodes) {
          // Find where the bottom left of this room would be if this node were the anchor
          int bottomLeftX = x - anchorNode.x;
          int bottomLeftY = y - anchorNode.y;
          if (bottomLeftX < 0 || bottomLeftY < 0) {
            continue;
          }
          RoomAnchor roomAnchor = new RoomAnchor(room, bottomLeftX, bottomLeftY);
          if (IsRoomAnchorValid(roomAnchor)) {
            roomAnchors.Add(roomAnchor);
          }
        }
        return roomAnchors;
      }
    
      bool IsRoomAnchorValid(RoomAnchor roomAnchor) {
        foreach (var node in roomAnchor.room.mapNodes) {
          if (!IsNodeValid(node, roomAnchor.x + node.x, roomAnchor.y + node.y)) {
            return false;
          }
        }
    
        int newOpenExits = GetNumOpenExits(roomAnchor);
        if (newOpenExits > exitsRemaining) {
          return false;
        }
        if (exitsRemaining > UNUSED_EXIT_TOLERANCE && newOpenExits == 0 &&
            roomAnchor.room.NumExits() >= openExits) {
          // This room is going to use up the last of the exits - don't let that happen unless we're at
          // the threshold
          return false;
        }
    
        return true;
      }
    
      int GetNumOpenExits(RoomAnchor roomAnchor) {
        int openExits = 0;
    
        foreach (var node in roomAnchor.room.mapNodes) {
          int x = roomAnchor.x + node.x;
          int y = roomAnchor.y + node.y;
    
          if (node.HasNorthExit() && map[x, y + 1] == null) {
            openExits++;
          }
          if (node.HasEastExit() && map[x + 1, y] == null) {
            openExits++;
          }
          if (node.HasSouthExit() && map[x, y - 1] == null) {
            openExits++;
          }
          if (node.HasWestExit() && map[x - 1, y] == null) {
            openExits++;
          }
        }
    
        return openExits;
      }
    
      bool IsNodeValid(MapNode node, int x, int y) {
        if (x > MAP_WIDTH || y > MAP_HEIGHT || map[x, y] != null) {
          return false;
        }
    
        if (x == 0 && node.HasWestExit() ||
            x == MAP_WIDTH - 1 && node.HasEastExit() ||
            y == 0 && node.HasSouthExit() ||
            y == MAP_HEIGHT - 1 && node.HasNorthExit()) {
          return false;
        }
    
        MapNode westNode = x > 0 ? map[x - 1, y] : null;
        MapNode eastNode = x < MAP_WIDTH - 1 ? map[x + 1, y] : null;
        MapNode southNode = y > 0 ? map[x, y - 1] : null;
        MapNode northNode = y < MAP_HEIGHT - 1 ? map[x, y + 1] : null;
    
        if (westNode != null && westNode.HasEastExit() && !node.HasWestExit()) {
          return false;
        }
        if (westNode != null && !westNode.HasEastExit() && node.HasWestExit()) {
          return false;
        }
        if (eastNode != null && eastNode.HasWestExit() && !node.HasEastExit()) {
          return false;
        }
        if (eastNode != null && !eastNode.HasWestExit() && node.HasEastExit()) {
          return false;
        }
        if (southNode != null && southNode.HasNorthExit() && !node.HasSouthExit()) {
          return false;
        }
        if (southNode != null && !southNode.HasNorthExit() && node.HasSouthExit()) {
          return false;
        }
        if (northNode != null && northNode.HasSouthExit() && !node.HasNorthExit()) {
          return false;
        }
        if (northNode != null && !northNode.HasSouthExit() && node.HasNorthExit()) {
          return false;
        }
    
        return true;
      }
    
      Room CreateRoom(Level level, Room room, int x, int y, bool forSpawn) {
        Room newRoom = Instantiate(room);
        RoomContents newContents;
        if (forSpawn) {
          newContents = Instantiate(
              possibleSpawnRoomContents[Utils.RandomIndex(0, possibleSpawnRoomContents.Count)]);
        } else {
          newContents = Instantiate(
              possibleRoomContents[Utils.RandomIndex(0, possibleRoomContents.Count)]);
        }
        
        newRoom.contents = newContents;
        newContents.transform.parent = newRoom.transform;
        UpdateRoomPosition(newRoom, x, y);
        //newRoom.SetActive(false);
        level.rooms.Add(newRoom);
    
        foreach (var node in newRoom.mapNodes) {
          node.mapX = x + node.x;
          node.mapY = y + node.y;
          map[node.mapX, node.mapY] = node;
        }
    
        return newRoom;
      }
    
      void UpdateRoomPosition(Room room, int x, int y) {
        float xPos = x * MapNode.UNIT_WIDTH;
        float yPos = y * MapNode.UNIT_HEIGHT;
        room.transform.position = new Vector2(xPos, yPos);
      }
    
      /**
       * Wrapper object to store a theoretical room together with the x/y coords of its bottom left
       * MapNode. This is used to check each possible placement of a large room to see where it can fit
       * on the map.
       */
      public class RoomAnchor {
        public Room room;
        public int x;
        public int y;
    
        public RoomAnchor(Room room, int x, int y) {
          this.room = room;
          this.x = x;
          this.y = y;
        }
      }
    }
    

    Thats pretty close algorithm I tried to use in my little roguelike. Stencyl doesn't let you use complex data structures in the design mode so I switched back to Unity, so much easier

  • Options
    GlalGlal AiredaleRegistered User regular
    edited May 2015
    How flexible is UE's Blueprint? I was thinking of giving it a spin in making a 2d platformer (ie, 3d with a side camera and an orthographic projection), but before I waste time, is that even within the scope of it or would I need to dip into code? Mainly an issue with physics really, I'd want either an all fake and hand-crafted or a mix of a simulation with edge-case handling. Could I use Blueprint for most of it and just plug my own code in for that specific case?

    Glal on
  • Options
    MahnmutMahnmut Registered User regular
    Glal wrote: »
    How flexible is UE's Blueprint? I was thinking of giving it a spin in making a 2d platformer (ie, 3d with a side camera and an orthographic projection), but before I waste time, is that even within the scope of it or would I need to dip into code? Mainly an issue with physics really, I'd want either an all fake and hand-crafted or a mix of a simulation with edge-case handling. Could I use Blueprint for most of it and just plug my own code in for that specific case?

    You could absolutely do all that in Blueprint, even if you wanted to turn off Unreal physics and move all your dudes yourself. I would probably start with a C++ class so I could write my physics stuff in a more compact format, then tweak values through blueprints, but yeah.

    Steam/LoL: Jericho89
  • Options
    KashaarKashaar Low OrbitRegistered User regular
    Glal wrote: »
    How flexible is UE's Blueprint? I was thinking of giving it a spin in making a 2d platformer (ie, 3d with a side camera and an orthographic projection), but before I waste time, is that even within the scope of it or would I need to dip into code? Mainly an issue with physics really, I'd want either an all fake and hand-crafted or a mix of a simulation with edge-case handling. Could I use Blueprint for most of it and just plug my own code in for that specific case?

    You can create entire complex games in Blueprint, so yeah! That's all well possible :)

    Indie Dev Blog | Twitter | Steam
    Unreal Engine 4 Developers Community.

    I'm working on a cute little video game! Here's a link for you.
  • Options
    GlalGlal AiredaleRegistered User regular
    Excellent. <3
    I can do C++ just fine, but for hobby projects I'd honestly prefer not to unless I have to. I liked Stencyl in concept (reminded me of my Klik'n'Play days way back in the day), but at a certain logic complexity handling it just became unwieldy, both the interface and behaviour.

  • Options
    rembrandtqeinsteinrembrandtqeinstein Registered User regular
    found this article about matching your orthographic camera to your screen resolution in Unity:
    http://absinthegames.com/unity3d-understanding-orthographic/

    tl;dr you set your orthographic camera size to 50% of your screen resolution height and 1 Unity unit will equal 1 pixel on the screen

  • Options
    GlalGlal AiredaleRegistered User regular
    edited May 2015
    Also, if you then import 3DS Max models with those settings 1 unit in Max will equal 1 pixel in Unity.

    [edit] Another fun gotcha is that different graphics standards round the pixels differently, so if you have pixel-perfect textures you might want to test out the results on different machines/hardware and make sure you're not getting a 1px offset on your textures (invisible with modern games, painfully obvious with pixel games). I believe DirectX rounds one way and OpenGL the other? I had to offset my textures 0.5px on two sides to get them displaying properly.

    Glal on
  • Options
    KhavallKhavall British ColumbiaRegistered User regular
    It really irks me that Unreal uses "Blueprint" to refer to both its scripting thing and prefabs.

    I mean I kind of get where they're coming from, but it still sort of annoys me that I'm never really sure what exactly I'm trying to edit when I hit anything with the word "Blueprint" on it.

  • Options
    PhyphorPhyphor Building Planet Busters Tasting FruitRegistered User regular
    I've never used prefabs, but as I understand it, it's done by creating an actor with all of the meshes as components, so it's functionally equivalent to any other blueprint

  • Options
    KhavallKhavall British ColumbiaRegistered User regular
    edited May 2015
    Well I mean in Unity Prefabs are basically the equivalent to what Unreal calls a "Blueprint Class" I guess?

    It's just confusing to me that there's Blueprint Classes and Blueprint Scripting, and they're both sometimes just referred to as "Blueprints"

    It would be nice if there was some more terminology difference between them is all.



    Also for some reason I've just never been good at Visual programming, so ultimately I don't even really care about Blueprint scripting because I don't even want to use it.
    But I pretty much write everything to be somewhat procedurally generated, so I really heavily rely on prefabs.

    Khavall on
  • Options
    KashaarKashaar Low OrbitRegistered User regular
    Colloquially yeah, Blueprint can mean "a blueprint", or the system you use to make those. I don't think it's much of an issue, context usually provides enough information to distinguish which one is being referred to...

    UE's equivalent to Unity's prefabs are just "actors" - Unreal's game objects, which can be composed of components no matter whether they're made in code or in Blueprint.

    Indie Dev Blog | Twitter | Steam
    Unreal Engine 4 Developers Community.

    I'm working on a cute little video game! Here's a link for you.
  • Options
    PhyphorPhyphor Building Planet Busters Tasting FruitRegistered User regular
    Khavall wrote: »
    Well I mean in Unity Prefabs are basically the equivalent to what Unreal calls a "Blueprint Class" I guess?

    It's just confusing to me that there's Blueprint Classes and Blueprint Scripting, and they're both sometimes just referred to as "Blueprints"

    It would be nice if there was some more terminology difference between them is all.



    Also for some reason I've just never been good at Visual programming, so ultimately I don't even really care about Blueprint scripting because I don't even want to use it.
    But I pretty much write everything to be somewhat procedurally generated, so I really heavily rely on prefabs.

    Oh, yeah it's just that under the hood they're actually the same thing. A blueprint is an object + scripting, though you can opt to only do one or the other. The only exception is the level blueprint which is basically scripting only

  • Options
    IzzimachIzzimach Fighter/Mage/Chef Registered User regular
    Well people do usually refer to specific types of blueprints if it's unclear, like "Actor Blueprint" or "Animation Blueprint". But yeah, without some context the term "Blueprint" is so vague it's kind of useless.

  • Options
    HallowedFaithHallowedFaith Call me Cloud. Registered User regular
    Having a fun time experimenting today. I'm all super nerd raged up for Splatoon so I had a dip of inspiration last night. Taking the time to learn surface drawing and ended up with this.

    DJ7jH4E.gif

    I'm making video games. DesignBy.Cloud
  • Options
    DarkMechaDarkMecha The Outer SpaceRegistered User regular
    I found a way to adapt Unity's navmesh system for 2d games! This frees me up to be able to make whatever I want! Huzzah!!

    Steam Profile | My Art | NID: DarkMecha (SW-4787-9571-8977) | PSN: DarkMecha
  • Options
    HallowedFaithHallowedFaith Call me Cloud. Registered User regular
    Some more inkling stuff today.
    n8onN8z.gif

    I'm making video games. DesignBy.Cloud
  • Options
    GlalGlal AiredaleRegistered User regular
    Needs bottomless pits. The real ink starts here.

  • Options
    HallowedFaithHallowedFaith Call me Cloud. Registered User regular
    Honestly, I have no idea what I am doing with it right now, just playing around with ideas. I figured something along the lines of, you can't walk on color that is not your current color or you die.

    I'm making video games. DesignBy.Cloud
  • Options
    ZekZek Registered User regular
  • Options
    GnomeTankGnomeTank What the what? Portland, OregonRegistered User regular
    Glal wrote: »
    Excellent. <3
    I can do C++ just fine, but for hobby projects I'd honestly prefer not to unless I have to. I liked Stencyl in concept (reminded me of my Klik'n'Play days way back in the day), but at a certain logic complexity handling it just became unwieldy, both the interface and behaviour.

    I find a hybrid to work best honestly. Generally I start my projects as C++, and then build the game logic in Blueprint using the C++ classes as the base of the Blueprints. This gives me an easy place to implement things that are easier/faster in C++, in C++, while still allowing me to do game code in the more natural Blueprint space.

    Sagroth wrote: »
    Oh c'mon FyreWulff, no one's gonna pay to visit Uranus.
    Steam: Brainling, XBL / PSN: GnomeTank, NintendoID: Brainling, FF14: Zillius Rosh SFV: Brainling
  • Options
    GlalGlal AiredaleRegistered User regular
    Sound advice for coding in general, really. Work at high level when it's making you productive, then switch to lower level when implementing something would just turn into a hacky slog to work around the inherent limitations otherwise.

  • Options
    rembrandtqeinsteinrembrandtqeinstein Registered User regular
    edited May 2015
    Glal wrote: »
    Excellent. <3
    I can do C++ just fine, but for hobby projects I'd honestly prefer not to unless I have to. I liked Stencyl in concept (reminded me of my Klik'n'Play days way back in the day), but at a certain logic complexity handling it just became unwieldy, both the interface and behaviour.

    I also liked Stencyl but what killed it for me was the lack of data structures more complicated than 1 dim arrays. The last version added hashmaps but anything remotely complicated gets extremely cumbersome to deal with. You end up doing a lot of ugly string parsing, even for something as simple as an x,y coordinate object. In Unity I just make a "Coords" object with x and y ints and pass that around. And that lets me encapsulate lots of other stuff like error checking and debug messages.

    Also the last version of Stencyl I worked with had a mean bug where list variables set in the IDE weren't initialized sometimes in game. So you had to initialize all of your data in your code at the start of your game, it was too much.

    rembrandtqeinstein on
  • Options
    KhavallKhavall British ColumbiaRegistered User regular
    edited May 2015
    Oh boy.

    C# to C++ is...


    Going to be a challenge.

    Hey short list so far today of things Khavall never had to really worry about before:
    good Header files
    Pointers
    Proper use of scope resolution operators outside of like once or twice



    C# already feels like a magical fantasy language where I just sort of type whatever I want and through some dark magic it all works well without me ever having to think too hard.


    Though I guess this is exactly what I thought of about Java when I was learning C#. And exactly what I thought about Python when I was learning Java...

    Khavall on
  • Options
    EnigmedicEnigmedic Registered User regular
    Khavall wrote: »
    Oh boy.

    C# to C++ is...


    Going to be a challenge.

    Hey short list so far today of things Khavall never had to really worry about before:
    good Header files
    Pointers
    Proper use of scope resolution operators outside of like once or twice



    C# already feels like a magical fantasy language where I just sort of type whatever I want and through some dark magic it all works well without me ever having to think too hard.


    Though I guess this is exactly what I thought of about Java when I was learning C#. And exactly what I thought about Python when I was learning Java...

    Well that could even be applied to spoken languages. I can throw down a lot of nonsense in English and someone will probably understand it, but if I try to speak in a language I don't know, it will be some google translate garbage.

  • Options
    JepheryJephery Registered User regular
    edited May 2015
    Khavall wrote: »
    Oh boy.

    C# to C++ is...


    Going to be a challenge.

    Hey short list so far today of things Khavall never had to really worry about before:
    good Header files
    Pointers
    Proper use of scope resolution operators outside of like once or twice



    C# already feels like a magical fantasy language where I just sort of type whatever I want and through some dark magic it all works well without me ever having to think too hard.


    Though I guess this is exactly what I thought of about Java when I was learning C#. And exactly what I thought about Python when I was learning Java...

    It is doing dark magic for you behind the scenes so you don't have to think about it. But sometimes you need to take the dark magic into your own hands.

    Jephery on
    }
    "Orkses never lose a battle. If we win we win, if we die we die fightin so it don't count. If we runs for it we don't die neither, cos we can come back for annuver go, see!".
  • Options
    KhavallKhavall British ColumbiaRegistered User regular
    edited May 2015
    Yeah I'm sure that once I start to "get" C++'s flow I'll totally understand the importance of all this stuff, and start to appreciate it.

    Just boy, didn't expect to spend the whole morning just setting up some public variables.

    And probably doing it in a really dumb way.

    Khavall on
  • Options
    HallowedFaithHallowedFaith Call me Cloud. Registered User regular
    That's why I can't get into higher level languages, I don't want to spend all day writing code and not seeing a game being made. I can write and operate in those languages but doing so is too slow for me.

    I'm making video games. DesignBy.Cloud
  • Options
    JepheryJephery Registered User regular
    That's why I can't get into higher level languages, I don't want to spend all day writing code and not seeing a game being made. I can write and operate in those languages but doing so is too slow for me.

    You mean lower level languages. Higher level means higher level of abstraction.

    Sorry for the nitpicking lol.

    }
    "Orkses never lose a battle. If we win we win, if we die we die fightin so it don't count. If we runs for it we don't die neither, cos we can come back for annuver go, see!".
  • Options
    HallowedFaithHallowedFaith Call me Cloud. Registered User regular
    Yeah yeah, that. I thought C+ was a higher level, but I just educated myself.

    You guys keep bitwising your std's or whatever, and I'll just be over here writing simple functions. :P

    I'm making video games. DesignBy.Cloud
  • Options
    amnesiasoftamnesiasoft Thick Creamy Furry Registered User regular
    But... bit manipulation is so much fun!

    I think I may be in the minority and that might be why I was the only person in my algorithms class to generate power sets using bit masks.

    steam_sig.png
  • Options
    MachwingMachwing It looks like a harmless old computer, doesn't it? Left in this cave to rot ... or to flower!Registered User regular
    Header files are so goddamn stupid and maybe 70% of the reason I've avoided c++ so far

    l3icwZV.png
  • Options
    KhavallKhavall British ColumbiaRegistered User regular
    I'm still not sure how exactly I'm "supposed" to use header files.

    Right now I've just started using it as a really stupid way to declare public variables. Should I also be declaring my functions in it? Should I be going more crazy in the header or the cpp file?

    I sort of get the feeling that I should use the header as little as possible, but at the same time, what's even then the point of having it, if I'm just using it to declare some global variables?

    Or are they just stupid and dumb and I should get used to feeling like they're stupid and dumb?

  • Options
    Jubal77Jubal77 Registered User regular
    Khavall wrote: »
    I'm still not sure how exactly I'm "supposed" to use header files.

    Right now I've just started using it as a really stupid way to declare public variables. Should I also be declaring my functions in it? Should I be going more crazy in the header or the cpp file?

    I sort of get the feeling that I should use the header as little as possible, but at the same time, what's even then the point of having it, if I'm just using it to declare some global variables?

    Or are they just stupid and dumb and I should get used to feeling like they're stupid and dumb?

    C++ is fun. But I am happy that I can choose never to touch it again.

    This outlines why you want to use them.

    http://www.cplusplus.com/forum/articles/10627/

  • Options
    agoajagoaj Top Tier One FearRegistered User regular
    Khavall wrote: »
    I'm still not sure how exactly I'm "supposed" to use header files.

    Right now I've just started using it as a really stupid way to declare public variables. Should I also be declaring my functions in it? Should I be going more crazy in the header or the cpp file?

    I sort of get the feeling that I should use the header as little as possible, but at the same time, what's even then the point of having it, if I'm just using it to declare some global variables?

    Or are they just stupid and dumb and I should get used to feeling like they're stupid and dumb?

    Header files are for sharing declarations (classes,methods,functions,variables) between different files, but they aren't actually any different from .c files.
    C/C++ let's you declare prototypes, the minimal amount of information you need to use a function/class. You can use prototypes to reference things that are declared elsewhere or later in the file.
    //Prototype
    void Jump(bool superjump);
    
    void Controls()
    {
       Jump(true);
    }
    
    void Jump(bool superjump)
    {
    //actual code
    }
    
    This works even if Jump's code is put in a different file. You could copy the prototype around and put it into the files where you need to call that function, this is what H files are there to help with.

    The #include "Jump.h" command is literally taking the code from Jump.h and pasting it in there. You could use include to copy and paste any file into your code, it's not just .h files.
    Why not just include the .cpp file with the full function? Because that copies the text and now you have defined two or more functions with the same name and C can't deal with that.

    Includes let you group these prototypes so you can easily reference them in other files, but you quickly run into a problem where two files have to include eachother and that leads to an endless loop. You get around that with Include guards
    //IF FILENAME_H is not defined...
    #ifndef FILENAME_H
    //Define FILENAME_H
    #define FILENAME_H
    //Code
    #include "someothercode.h"
    //Code
    //Code
    #endif
    
    So we've got the C Preprocessor running over your file, copying in your includes, then it runs on that included code. If #define FILENAME_H has been set already it removes the code between #ifndef and #endif, breaking the include loop while still including everything once.

    H files are a workaround for the C language that are thankfully not required in modern languages.

    ujav5b9gwj1s.png
  • Options
    KhavallKhavall British ColumbiaRegistered User regular
    Ok that makes a lot of sense then.


    So it's really dumb for the sort of stuff I've been needing it for, since my coding is pretty basic for the most part(and when it's not, it's not in a way that's not very heavy computationally anyways)

    At least there's a pretty good reason though, thanks.

  • Options
    KhavallKhavall British ColumbiaRegistered User regular
    edited May 2015
    Well, after a day of tearing my hair out, realizing I wasn't even approaching the thing I was approaching wrong right, getting weird errors about how all of sudden so and so dependency was broken because of something dumb I'd done, I've thrown everything out and started over.

    Luckily I hadn't really done much, but hey.

    Progress?



    EDIT: Also, before I start on some other dumb thing, the equivalent to the GameManager object is the GameMode class, right? And does that need to be attached to a physical in-game object?

    I feel like even after reading the "Unreal engine for Unity developers" thing like a million times I'm still totally in the dark about how Unreal works.

    Khavall on
Sign In or Register to comment.