Welcome, Guest. Please login or register.

Login with username, password and session length

 
Advanced search

1411319 Posts in 69331 Topics- by 58384 Members - Latest Member: Winning_Phrog

April 03, 2024, 12:55:36 PM

Need hosting? Check out Digital Ocean
(more details in this thread)
  Show Posts
Pages: 1 ... 6 7 [8] 9
141  Community / DevLogs / Re: Soldier Of - 3D GBC-Styled Zelda-like - WINDOWS DEMO UP! on: June 22, 2012, 03:44:24 PM
Similar to what SolarLune has done, I would give each interactable object a unique id. Right now the original position is acting as this but if for some reason two objects could potentially have the same original position then you could use a unique id. I subscribe to the manager design pattern and so I would have an InteractableManager that would take care of all of this for me.
142  Community / DevLogs / Re: Crea - Now with a video! on: June 18, 2012, 02:47:02 PM
Got a large update today. The last week I have been in the zone and have gotten a great deal done. First off, we reworked our website a little. In my last update I said I was working on implementing plants. At that point I was still in the designing phase for them. Since then I have finished implementing them and much more.

For every feature my mantra is easily moddable but lots of control. All of the supported content up to this point has had one form of communication - engine asking for the entities components which are returned in component definition form. I struggled quite a bit while attempting to fit the plants into this format. I finally came to my senses and realized what I had to do.

All of the plant logic resides inside of python. How the plant grows, how it visually looks, how it is harvested, and even how it is planted. With this solution, any modder has unlimited control. As for the “easily” part of my mantra, I am wrapping the core plant concepts up into nice little python classes which are extremely simple to use. I have included the code below for those interested in its awesomeness.

Because of this approach I have had to go through my entire game engine and expose it to python. This is something I have been putting off because I wasn’t sure of the requirements, boost python is a little scary and I knew it was going to be quite an undertaking. With this beast finally slain, creating new content will be much easier and have even more freedom.

Here are some screenshots featuring the plants that can grow overtime and be interacted with. There is also an early version of the grass. Right now the grass just grows on soil and is destroyed when the tile underneath it is removed. Later today I plan to make grass occasionally spread to nearby areas as if seeds were dispersed.



You can harvest the trees too!



This is the Zebra tree script that most people will see and have to worry about. I hope most of this is self explanatory. We are adding the different components to the zebra tree entity and the ZebraTree class is used to override the default properties of the tree (which can be seen below). We can add bases, trunks crowns and saplings images and they will be randomly used in the appropriate places. We can also override many other properties such as the seed it produces how tall it can grow, and how fast it can grow.

Syntax Highlighted Source
Code:
name = "Zebra Tree"

add(ModularRender())

interactable = Interactable()
add(interactable)

class ZebraTree(Tree):
    trunks = [TreeImage("mods/base/plant/tree/zebra/trunk1.png", 2, 28), \
            TreeImage("mods/base/plant/tree/zebra/trunk2.png", 2, 28), \
            TreeImage("mods/base/plant/tree/zebra/trunk3.png", 23, 28)]
    crowns = [TreeImage("mods/base/plant/tree/zebra/crown1.png", 34, 101), \
              TreeImage("mods/base/plant/tree/zebra/crown2.png", 31, 98)]
    saplings = [TreeImage("mods/base/plant/tree/zebra/sapling.png", 8, 33)]
    seed = "mods/base/plant/tree/zebra/seed.ce"

    def __init__(self, entity, organic):
        super(ZebraTree, self).__init__(entity, organic)


def createZebraTree(entity, organic):
    return ZebraTree(entity, organic)

add(Organic(createZebraTree))



Here is the Zebra seed script which is really simple. As with all content entity scripts we add the needed components, this time a Render, Item and Interactable components. The important part here is that we add an interaction “use” and provide the “useSeed” function which is defined in the tree script just below this one. To make this function reusable the plant the seed creates needs to be bound to the function provided - in this case we provide the path to the zebra tree.

Syntax Highlighted Source
Code:
import functools

name = 'Zebra Seed'
render = Render('mods/base/plant/tree/zebra/seed.png')
add(render)
item = Item()
item.stack = 999
item.delay = 200
add(item)

interactable = Interactable()
interactable.add("use", functools.partial(useSeed, "mods/base/plant/tree/zebra/zebra.ce"))
add(interactable)



Now for the meat of the tree logic. Here is the tree script which contains the Tree class and useSeed function that are used in the above scripts. As with everything this is still in the works but is most of the way there. I’m not going to go into detail in this now since there is so much going on but if you understand it then awesome. Once things start becoming finalized we’ll write some official documentation on these sorts of things.

Syntax Highlighted Source
Code:
import random

class TreeImage:
    def __init__(self, path, center, height):
        self.path = path
        self.center = center
        self.height = height

TreePart = enum(BASE=1, TRUNK=2, CROWN=3, SAPLING=4)

class TreeSprite:
    def __init__(self, part, index):
        self.index = index
        self.part = part
        self.sprite = Sprite()

class Tree(object):
    bases = []
    trunks = []
    crowns = []
    saplings = []
    #Path to the seed content script
    seed = ""
    #The range of the number of seeds that will drop from the crown
    seedRange = (1, 3)
    wood = "mods/base/item/raw/wood.ce"
    growthTimeMin = 60 * 1000 #1 minute
    growthTimeMax = 5 * 60 * 1000 #5 minutes
    #How much time it takes to recover from a hit
    recoveryTime = 10000
    #How much life each part of the tree has - how many hits it can take
    partLife = 3
    trunkRange = (2, 6)

    def __init__(self, entity, organic):
        self.organic = organic

        #TODO: Is this reasonable to expect players to be network aware?
        if not Game.get().network.isHost():
            return

        entity.interactable.add("harvest", self.onHarvest)
        entity.interactable.add("removeSupport", self.onRemoveSupport)
        self.addGrowthTimer()

        #Start it off as a sapling
        self.stage = 0
        self.maxStage = random.randint(self.trunkRange[0], self.trunkRange[1])
        self.sprites = [TreeSprite(TreePart.SAPLING, random.randint(0, len(self.saplings) - 1))]
        self.construct()

    def addGrowthTimer(self):
        Game.get().timer.add(random.randint(self.growthTimeMin, self.growthTimeMax), self.grow)

    def grow(self):
        if self.stage == -1:
            return
        self.stage += 1

        if self.stage is 1:
            #Clear out the sapling and append the tree base and crown
            self.sprites = []
            if self.bases:
                self.sprites.append(TreeSprite(TreePart.BASE, random.randint(0, len(self.bases) -1)))
            if self.crowns:
                self.sprites.append(TreeSprite(TreePart.CROWN, random.randint(0, len(self.crowns) -1)))
        if self.stage >= 1:
            trunk = TreeSprite(TreePart.TRUNK, random.randint(0, len(self.trunks) - 1))
            if self.crowns:
                self.sprites.insert(-1, trunk)
            else:
                self.sprites.append(trunk)

        self.construct()
        if self.stage is not self.maxStage:
            self.addGrowthTimer()

    def getImage(self, sprite):
        if sprite.part is TreePart.BASE:
            return self.bases[sprite.index]
        elif sprite.part is TreePart.TRUNK:
            return self.trunks[sprite.index]
        elif sprite.part is TreePart.CROWN:
            return self.crowns[sprite.index]
        elif sprite.part is TreePart.SAPLING:
            return self.saplings[sprite.index]
        else:
            raise ValueError("TreeSprite contains unknown tree part: ", sprite.part)

    def construct(self):
        print "Building the tree at stage:", self.stage
        height = 0
        sprites = []
        for sprite in self.sprites:
            image = self.getImage(sprite)
            height -= image.height
            sprite.sprite.position.x = -image.center
            sprite.sprite.position.y = height
            self.organic.setImage(image.path, sprite.sprite)
            sprites.append(sprite.sprite)
        self.organic.onConstruct(sprites)

    def onHarvest(self, args):
        entity = args["entity"]
        sprite = entity.modularRender.getTopSprite(args["position"])
        index = 0
        for s in self.sprites:
            if s.sprite is sprite:
                break
            index += 1

        game = Game.get()
        parent = self.organic.getParent()
        if not parent:
            print "Could not find parent entity for the plant."
            return

        damageId = "%d-%d" % (parent.id, index)
        if not game.damage(damageId, 1, self.partLife, self.recoveryTime):
            #return if we haven't done enough damage to the targeted tree part
            return

        #ignore if at the top of the tree
        if index == len(self.sprites):
            return

        self.destroyAtIndex(index)


    def destroyAtIndex(self, index):
        #Create the dropped items in the world
        game = Game.get()
        woodId = game.mod.getContent(self.wood).id
        for s in self.sprites[index:]:
            image = self.getImage(s)
            centerY = image.height / 2
            position = s.sprite.getPosition()
            position.x += image.center
            position.y += centerY
            woodPosition = position
            woodPosition.x += random.randint(-image.center, image.center)
            woodPosition.y += random.randint(-centerY, -centerY)
            print "Creating dropped wood at position (%d, %d)" % (woodPosition.x, woodPosition.y)
            game.dropped.create(woodId, 1, woodPosition, Vectorf(0, 8))

            if s.part is TreePart.CROWN and self.seed:
                seedId = game.mod.getContent(self.seed).id
                for x in xrange(0, random.randint(self.seedRange[0], self.seedRange[1])):
                    seedPosition = position
                    seedPosition.x += random.randint(-image.center, image.center)
                    seedPosition.y += random.randint(-centerY, centerY)
                    print "Creating dropped seed at position (%d, %d)" % (seedPosition.x, seedPosition.y)
                    game.dropped.create(seedId, 1, seedPosition, Vectorf(0, 8))

        #remove the targeted sprite and all of the sprites above it
        self.sprites = self.sprites[:index]

        if self.sprites:
            #Reconstruct the graphics for the tree
            self.organic.onConstruct([sprite.sprite for sprite in self.sprites])
            #Set the stage to -1 signifying that it cannot grow anymore
            self.stage = -1
        else:
            #The entire tree was destroyed. Destroy the entity.
            parent = self.organic.getParent()
            if parent:
                parent.destroy()

    def onRemoveSupport(self, args):
        #First check to see if the base (or bottom trunk) is actually over the tile being changed
        sprite = self.sprites[0]
        spriteArea = sprite.sprite.getRect()
        if not spriteArea.intersects(args["area"]):
            #No overlap so this is a false alarm
            return

        if args["forced"]:
            #The support is being forcefully removed. Destroy the entire tree
            self.destroyAtIndex(0)
        else:
            #Cancel the request
            args["canceled"] = True

    def save_bad(self, stream):
        import pdb
        pdb.set_trace()
        stream << self.stage
        stream << len(self.sprites)
        for sprite in self.sprites:
            stream << self.part
            stream << self.index

    def load_bad(self, stream):
        stream >> self.stage
        spriteCount = 0
        stream >> spriteCount
        self.sprites = []
        for x in xrange(0, spriteCount):
            part = 0
            index = 0
            stream >> part
            stream >> index
            self.sprites.append(TreeSprite(part, index))
        self.construct()

    def pack_bad(self, packet):
        self.save(packet)

    def unpack_bad(self, packet):
        self.load(packet)

def useSeed(plant, args):
    #First calculate the position of the new tree and see if it is ok
    position = args["position"]
    ground = World.get().layer["ground"]

    #If the tile clicked on is solid as well as the tile above it then do not allow seed planting
    tilePos = ground.getTilePosition(position)
    if ground.getTile(tilePos) is not 0 and ground.getTile(Vector(tilePos.x, tilePos.y + 1)):
        return

    tilePos = ground.getTileInDirection(position, Vector(0, 1))
    verticalPos = tilePos.y * TileSystem.TILE_SIZE
    if verticalPos > (position.y + 2 * TileSystem.TILE_SIZE):
        return
    position.y = verticalPos

    game = Game.get()
    contentId = game.mod.getContent(plant).id
    tree = game.entity.create(contentId, True)

    tree.modularRender.setPosition(position)
    print "Created new tree at (%d, %d)" % (position.x, position.y)
    World.get().layer["active"].add(tree)
    args['decrement'] = 1



Lastly, I wanted to throw in the grass code which I’m happy about because I was able to write it without making any engine code changes. There is still in the works but I have the basics down. I will likely do the same for the grass that I did for the tree and have a base Grass class and allow for inheriting and changing the properties without having to worry about the logic.

Syntax Highlighted Source
Code:
name = "Grass"

class GrassImage(object):
    def __init__(self, path, height):
        self.path = path
        self.height = height

class GrassSprite(object):
    def __init__(self, index):
        self.index = index
        self.sprite = Sprite()

class Grass(object):
    images = [GrassImage("mods/base/plant/grass.png", 5)]
    sides = []
    growthTimeMin = 2 * 60 * 1000 #2 minutes
    growthTimeMax = 5 * 60 * 1000 #5 minutes
    spreadTimeMin = 8 * 60 * 1000 #8 minutes
    spreadTimeMax = 10 * 60 * 1000 #10 minutes

    def __init__(self, entity, organic):
        print "Creating grass."
        self.organic = organic
        if not Game.get().network.isHost():
            return
        entity.interactable.add("removeSupport", self.onRemoveSupport)
        grass = GrassSprite(random.randint(0, len(self.images) - 1))
        image = self.images[grass.index]
        grass.sprite.position.y = -image.height
        self.organic.setImage(image.path, grass.sprite)
        self.grass = [grass]
        self.construct()
        self.addGrowthTimer()

    def addGrowthTimer(self):
        Game.get().timer.add(random.randint(self.growthTimeMin, self.growthTimeMax), self.grow)

    def grow(self):
        self.addGrowthTimer()
        world = World.get()
        ground = world.layer["ground"]
        if len(self.grass) >= 30:
            #TODO: Check to see if the grass can spread and create a new grass entity
            return
        #The grass is store from left to right [leftmost:rightmost]
        #First check to see if the leftmost grass can spread more left
        self.growOutward(ground, 0, -1)
        self.growOutward(ground, len(self.grass) - 1, 1)
        self.construct()

    def growOutward(self, ground, index, direction):
        grassSprite = self.grass[index].sprite
        position = grassSprite.getPosition()
        position.x += TileSystem.TILE_SIZE * direction
        position.y += TileSystem.TILE_SIZE
        tilePos = ground.getTilePosition(position)
        if ground.getTile(tilePos):
            tile = ground.getTileComponent(tilePos)
            if 'soil' in tile.getGroups() and random.randint(0, 1):
                #Soil! We found it and passed the random test. Lets add it!
                grass = GrassSprite(random.randint(0, len(self.images) - 1))
                image = self.images[grass.index]
                grass.sprite.position.x = grassSprite.position.x + (TileSystem.TILE_SIZE * direction)
                grass.sprite.position.y = grassSprite.position.y
                self.organic.setImage(image.path, grass.sprite)
                if direction is -1:
                    self.grass.insert(0, grass)
                else:
                    self.grass.append(grass)

    def isTouchingTile(self, ground, tilePos):
        grassTile = ground.getTilePosition(grass.sprite.getPosition())
        return grassTile.x == tilePos.x and grassTile.y + 1 == tilePos.y

    def onRemoveSupport(self, args):
        tilePos = args["tilePos"]
        ground = World.get().layer["ground"]
        self.grass = [grass for grass in self.grass if not self.isTouchingTile(ground, tilePos, grass)]
        if self.grass:
            self.construct()
        else:
            #No more grass - go ahead and destroy this grass.
            parent = self.organic.getParent()
            if parent:
                parent.destroy()

    def construct(self):
        self.organic.onConstruct([grass.sprite for grass in self.grass])

def createGrass(entity, organic):
    return Grass(entity, organic)

add(ModularRender())
add(Interactable())
add(Organic(createGrass))



Thanks for reading through all of this! I know it is a lot. I’m interested to hear what you think of this.
143  Community / DevLogs / Re: Chroma on: June 17, 2012, 08:35:42 AM
Looking good!

I see the less subtle one (closer to obvious imo). Took me about 3 seconds of looking at it to see it. However, I fail to see the more subtle thing. I'll just keep staring at it for awhile. Smiley
144  Community / DevLogs / Re: Diluvium on: June 08, 2012, 04:57:16 PM
Yeah, 64-bit. I checked the permissions. Nothing special about them - I'm an admin. I even tried "Run as Administrator" and I get the same error.

Does Unity log somewhere that I could look at? I looked in the usual places (AppData/Local and Roaming as well as ProgramData but didn't see anything. Perhaps it has the option to turn logging on and I could try a special build?
145  Community / DevLogs / Re: Soldier Of - 3D GBC-Styled Zelda-like - WINDOWS DEMO UP! on: June 08, 2012, 02:39:05 PM
Multiplayer is definitely a beast best considered from the beginning. I did not consider multiplayer for my current project until after getting a decent chunk of the engine done. Because of this I ended up having to rewrite a fair amount of the code and even redesign a few things.

I've been following Soldier Of for awhile and I'm not sure how much multiplayer would be adding to it. This is of course completely up to you. If you do decide to go ahead with it I would say that you should expect to spend at least 2 weeks upfront and probably a few more over the course of the project.
146  Community / DevLogs / Re: Diluvium on: June 07, 2012, 07:28:14 PM
Tried on my home computer and was upgraded to an error message. All I did was drag and drop the contents of the zip into this previously empty directory.

147  Community / DevLogs / Re: Crea - Now with a video! on: June 07, 2012, 03:51:45 PM
While I work on implementing plants into the game our artist has been working on some trees. Here are some of them with the seed, sapling and fully grown stages.

Normal Tree


Marshmallow Tree


Zebra Tree


There are two more mentioned over at our blog. Smiley
148  Community / DevLogs / Re: Diluvium on: June 07, 2012, 01:11:05 PM
I am indeed 64-bit, but I doubt that you would need a 64-bit build. Typically 64-bit machines can run any 32-bit process using WOW64. I'll try it on my home computer this evening. But then again that is a Windows 7 64-bit machine.

Has anyone had success on Windows 7 64-bit?
149  Community / DevLogs / Re: Diluvium on: June 07, 2012, 12:07:40 PM
I attempted to play on my Windows 7 machine and when I launch the game it immediately exits. Are there any logs or something that I could look at or get you? Or more steps to installing than just unzipping and running?
150  Community / DevLogs / Re: Chroma on: June 07, 2012, 07:06:19 AM
I'm not really a massive fan of the whole kickstarter thing. I know some good stuff is being produced because of it and things like Indie Game the Movie have been a great success, but I don't like the idea of asking for money for something I have yet to finish.

I could live for a year or maybe a little more on savings anyway, it's still a risk to quit. It took me a long long time to get this job and if I need to get another at some point I may not be as lucky. I think I will take the jump at some point before this project is over, just gotta work stuff out first Smiley

Completely understandable. I'm in a similar situation. Looking forward to what you come up with. Smiley
151  Community / DevLogs / Re: Chroma on: June 06, 2012, 03:59:47 PM
Have you considered putting together a kickstarter campaign? I know I'd be more than willing to put down some money.
152  Community / DevLogs / Re: Crea - Now with a video! on: June 04, 2012, 06:28:17 PM
Yeah, I noticed that too. We should chat sometime - I'm sure it would prove to be interesting. Thanks.
153  Community / DevLogs / Re: Crea - Now with a video! on: June 04, 2012, 04:44:28 PM
154  Community / DevLogs / Re: Chroma on: June 04, 2012, 11:41:24 AM
Very awesome. I knew there was a reason why I would check this devlog everyday.
155  Community / DevLogs / Re: Crea on: June 04, 2012, 09:03:02 AM
I finally got around to putting together a quick video showing some features in Crea. Keep in mind that everything is still very much a work in progress. I'm interested to hear what you think.

In this video I show the modular composite animations, crafting, placing items down and a few other basic things.



Click image to go to the youtube video.
156  Community / DevLogs / Re: moonman on: June 03, 2012, 11:30:52 PM
@jmcmorris, thx for the tip Wink although can i recommend doing
Code:
if MAX_DIST*MAX_DIST> xd*xd+yd*yd then..
in future.. Smiley

@belimoth You'll be able to click anywhere on screen, in order to inspect things far away, select items from your inventory, use the menu, etc. and I think I'll change the cursor when you're able to use the currently wielded item on the block/target/thing under the cursor.

Haha, sure if you are doing this calculation a lot then you can save a little by doing that. I only do it when the player clicks so the few extra instructions probably don't make that big of a difference. Smiley
157  Community / DevLogs / Re: moonman on: June 03, 2012, 07:49:53 PM
Yeh, currently moonman can chop anywhere, but limiting the chopping radius is definitely in my TODO list. Wink

@ninjadodo thx, those poses are great! Smiley I've really got to spend some time on all the animations, they are really quite sucky at the moment. Shocked

I implemented this in my game. It is really easy. Just calculate the difference between the position clicked and the character call it xd and yd.

Code:
distance = sqrt(xd * xd + yd * yd)

Then you can limit the distance to whatever you want.

Code:
if distance > 100 then return
158  Community / DevLogs / Re: What's In The Box? on: June 03, 2012, 07:44:13 PM
I like the latest image. A large improvement over the original in my opinion. I also like the little guy and the animations - very smooth!
159  Community / DevLogs / Re: Crea on: June 01, 2012, 06:51:29 PM
Thanks zede!

Today I implemented a cool feature that I have dubbed "composite animations". Basically a given entity can have any number of different groups of animations playing at one time. This is in conjunction with the modular animations that I mentioned in my last update. So my engine technically supports modular composite animations - fancy!

This is being used for the character's front arm so that it can do its own thing such as swing a pickaxe while the character is running or jumping.

This is all exposed to the content scripts so it is possible to do anything with this. Such as a giant monster with multiple eyes blinking independently while the monster attempts to stomp on you. Why you would want to do that? Because it's awesome.

I imagine I'll be posting a video before too long showing off this feature along with many others. Smiley
160  Community / DevLogs / Re: Chroma on: May 30, 2012, 12:49:29 PM
I like the first one with the jacket. That one or the original is what I would go with.
Pages: 1 ... 6 7 [8] 9
Theme orange-lt created by panic