Battle Engine - Alpha 6 release, downloads in first post

Ideas and games that are not yet publicly in production. This forum also contains the pre-2012 archives of the Works in Progress forum.
Message
Author
User avatar
blakjak
Veteran
Posts: 224
Joined: Fri Dec 21, 2007 2:36 pm
Location: France
Contact:

Re: Battle Engine - Alpha 4 release, downloads in first post

#226 Post by blakjak » Wed Sep 29, 2010 1:41 pm

DaFool wrote: By any chance have you come across easy tools to generate isometric walk-cycles similar to the plenty on offer for RPG Maker type games? Then again, it's one thing to have low-resolution generic chibi pixelart in 4 frames and another matter entirely to have HD sprites like in Disgaea 4 where the minimum seems to be 8-16 frames.
I'm not sure I understand what part of the walk cycle making you' d need tools for : the animation of bones, the camera setup, the timeline loop, or the spritesheet rendering ?

For the spritesheet rendering and camera setup,there are links in the first pages of this threads to tools to maker them directly from Blender, plus a little software that can also pack different images in a sprite sheet.

For the walk cycle, it's a bit more complex as you have to animate your units with bones. But I think youu've already done that since you wrote about the size of your walkcycle animations =)

But if it can help feel free to use this Blender file as an example, I started with a basic character that's already setup with bones, a script called unihuman, and then made a little walk animation using Jake's link to 2d animation techniques. Then I just added an orthographic camera.
Attachments
iso_grid_walk_cycle.zip
(350.14 KiB) Downloaded 12 times

User avatar
blakjak
Veteran
Posts: 224
Joined: Fri Dec 21, 2007 2:36 pm
Location: France
Contact:

Re: Battle Engine - Alpha 4 release, downloads in first post

#227 Post by blakjak » Wed Sep 29, 2010 10:38 pm

The basic mechanics haven't, but then the basic mechanics of the FPS haven't changed much since Wolfenstein 3D back in 1992 (most of the improvement has been technological). Various titles - including several of Nippon Ichi's - have put new rules into the mix that result in quite a different game, all the same. Go play Phantom Brave and then come back and tell me it's the same game that UFO: Enemy Unknown was! It's admittedly not so much of an evolution as Gears of War to Wolf3D, but it's still development of the idea which distinguishes that game quite distinctly from others of its type.
Speaking of the tactical rpg's evolution, has anyone here played " Knights in the Nightmare" from Atlus ?

http://www.atlus.com/knights/

It's a wonderful little game, which proposes an interesting mix between the T-RPG genre and some aspects of danmakus, mostly dodging bullets.

User avatar
DaFool
Lemma-Class Veteran
Posts: 4171
Joined: Tue Aug 01, 2006 12:39 pm
Contact:

Re: Battle Engine - Alpha 4 release, downloads in first post

#228 Post by DaFool » Thu Sep 30, 2010 5:20 am

blakjak -> I meant something much more simpler such as
1. Pick the colors
2. Render out the spritesheet
3. Whola! Now use in your RPGMaker games.
I can't remember which website, but it was that basic. I'm not sure if there was an equivalent for isometric walkcycles.

Although now that you mentioned it, I did look at unihuman but ended up commissioning anyway since its more efficient and the end result is faster and better than what I could come up with. I am using, however, that isometric blend script you linked to in the Tigsource forums (version 1.04 I believe) for the machinery -- some of which I model myself, others I just buy off Turbosquid.

jack, Jake -> My target platform is any computer with minimum 720p graphics (my testbed is a laptop with Intel GMA HD). You're right I'm going to have to scale my stuff down to 3:1.

The reason for the super-big sprites is that I'm essentially making a point n click Adventure-SRPG hybrid. (Well we've experienced RPG-FPS hybrids (Fallout, Mass Effect), SRPG-3rd person shooter hybrids (Valkyria Chronicles), and just now blackjak mentioned an SRPG-schmup hybrid. )

I've read what Wadjet Eye games is up too, but no, I've come up with this idea independently. I've also read the musings in the Winter Wolves blog regarding wanting to explore the Adventure genre but art costs are so expensive, and I think I may have hit upon a production technique that will be most efficient. (The big 512x512 animations are essentially the same characters rendered in celshaded 3D doing Adventure-ish actions as opposed to combat-ish actions -- although most actions actually overlap). I'm not using BG tilesets but instead unified handpainted backdrops so it will feel more like an adventure game as opposed to a Diablo clone.

The way the Adventure will transition to SRPG will be marked by the message "Threat detected in the vicinity! Movement limits are now enforced!". The map then zooms out; baddies appear on the map; Grid Mode is activated (the gridlines will be overlayed on the previously clean map), and the main playable character will be able to summon and position her party members on adjacent squares; then turn-based tactical battle begins. Besides the walking around portion, most of the effects can be replicated by plain old Ren'Py up until the actual battle mode.

So in case I get stuck, and anybody wants to work on something that's more or less what I'm doing, then they can lend some programming assistance in exchange for not having to worry about the art assets.

Even if all this sounds neat, it's the actual execution that matters, so I can expect the final end result to be underwhelming compared to what I had envisioned in my head -- this could only be pulled off if the frame rates are any good.

User avatar
blakjak
Veteran
Posts: 224
Joined: Fri Dec 21, 2007 2:36 pm
Location: France
Contact:

Re: Battle Engine - Alpha 4 release, downloads in first post

#229 Post by blakjak » Fri Oct 01, 2010 2:59 am

DaFool wrote:blakjak -> I meant something much more simpler such as
1. Pick the colors
2. Render out the spritesheet
3. Whola! Now use in your RPGMaker games.
I can't remember which website, but it was that basic. I'm not sure if there was an equivalent for isometric walkcycles.
Oh ok =), then no, I haven't found anything like that yet =D

Your game seems so ambitious, can't wait to see what it plays like.

User avatar
DaFool
Lemma-Class Veteran
Posts: 4171
Joined: Tue Aug 01, 2006 12:39 pm
Contact:

Re: Battle Engine - Alpha 4 release, downloads in first post

#230 Post by DaFool » Sun Oct 10, 2010 1:33 pm

Finally got a movement demo going. I have a question regarding the panning controls -- I've been looking at the scripts and couldn't figure out how to reposition the buttons on the screen. They are in the top right corner, but even when I'm using an extended widescreen, they're still in the same position as in the 800x600 example. I also want to be able to break apart the controls so that I have them at the four edges of the screen.

This is the code from the scroll_demo.rpy:

Code: Select all

        # The 'PanningControls' extra is probably the most important one - it adds buttons on-screen to pan the view around.
        # The 'leftLabel', 'rightLabel' and so on parameters allow you to override the default text in the directional buttons.
        # The 'distance' parameter tells the controls Extra how far to pan the view in each direction when you click the button.
        battle.AddExtra(PanningControls(leftLabel=u'←', rightLabel=u'→', upLabel=u'↑', downLabel=u'↓', distance=250))
        
        # The 'ActionPanner' extra will automatically pan the view to centre on any action - so if an enemy moves, or attacks
        # one of your guys, the camera will centre on it (as best it can) so you can see it happen! 
        battle.AddExtra(ActionPanner())
        
        # Here we set the default values of the camera. If the camera X and Y are set to 0, then the camera starts looking at the 
        # top-left corner of the battlefield. The values we set here move the camera right (for positive X) or down (positive Y) across
        # the battlefield.
        battle.CameraX = 0
        battle.CameraY = 720
        
        # These values set the limits of the camera, so that the user (or ActionPanner, or any other mechanism) cannot pan any
        # further than you allow.
        # Each setting takes a tuple of two values, as seen below - the first value is the minimum allowed value for the camera in
        # that axis, the second is the maximum. Setting the second parameter lower than the first will result in weird behaviour.
        # Generally, you probably want the first value to be 0 (the left/top of the battlefield) and the second value to be the width/height
        # of the battlefield graphic minus the width/height of the screen.
        battle.CameraXLimit=(0, 2000 - 1280)
        battle.CameraYLimit=(0, 2000 - 720)
I'm not supposed to modify anything in engine_extras.rpy where it's defined, right?

User avatar
Jake
Support Hero
Posts: 3826
Joined: Sat Jun 17, 2006 7:28 pm
Contact:

Re: Battle Engine - Alpha 4 release, downloads in first post

#231 Post by Jake » Sun Oct 10, 2010 3:19 pm

DaFool wrote: I have a question regarding the panning controls -- I've been looking at the scripts and couldn't figure out how to reposition the buttons on the screen. They are in the top right corner, but even when I'm using an extended widescreen, they're still in the same position as in the 800x600 example. I also want to be able to break apart the controls so that I have them at the four edges of the screen.
You'll need to change some properties of the styles they're using - if you look in the assets.rpy file of the demo, around line 278 (alpha 4) there's a group of style definitions which place the buttons by pixel coordinates in the demos:

Code: Select all

    # Position the directional pan buttons in a D-pad in the top right
    style.PanButton['left'].xminimum = 50
    style.PanButton['left'].xmaximum = 50
    style.PanButton['left'].yminimum = 50
    style.PanButton['left'].ymaximum = 50
    style.PanButton['left'].xpos = 675
    style.PanButton['left'].ypos = 50
    
    style.PanButton['right'].xminimum = 50
    style.PanButton['right'].xmaximum = 50
    style.PanButton['right'].yminimum = 50
    style.PanButton['right'].ymaximum = 50
    style.PanButton['right'].xpos = 750
    style.PanButton['right'].ypos = 50
    
    style.PanButton['up'].xminimum = 50
    style.PanButton['up'].xmaximum = 50
    style.PanButton['up'].yminimum = 50
    style.PanButton['up'].ymaximum = 50
    style.PanButton['up'].xpos = 712
    style.PanButton['up'].ypos = 25
    
    style.PanButton['down'].xminimum = 50
    style.PanButton['down'].xmaximum = 50
    style.PanButton['down'].yminimum = 50
    style.PanButton['down'].ymaximum = 50
    style.PanButton['down'].xpos = 712
    style.PanButton['down'].ypos = 75
So if you modify those in your code, you should be able to re-skin and/or re-position your pan buttons.
DaFool wrote: I'm not supposed to modify anything in engine_extras.rpy where it's defined, right?
Yeah - my goal is that you should be able to do whatever you need to with the engine without modifying any of the files which start 'engine'. ;-)
Server error: user 'Jake' not found

User avatar
Jake
Support Hero
Posts: 3826
Joined: Sat Jun 17, 2006 7:28 pm
Contact:

Re: Battle Engine - Alpha 4 release, downloads in first post

#232 Post by Jake » Mon Oct 11, 2010 1:14 pm

Progress report!

I've more or less completed hex maps, including line-of-sight, using a doubled-up-rectangle-grid approach which doesn't absolutely perfectly model hexagon-tile line-of-sight, but it's a good-enough abstraction. The following image shows a Fighter being given the option of selecting any hex he has line-of-sight to:
screenshot0001.png
hex map line-of-sight example
If there are any ASL players on the forum maybe they can tell me whether my approach conforms to whatever the standard hex-hex LoS algorithm is in that... :3

I've also added some helper methods to Battlefield - "GetPositionsInLine", "GetPositionsInRadius" and "GetPositionsInRect", implemented as well as can reasonably be expected for each Battlefield type - to aid anyone writing extensions which perform particular effects. So if you wanted to write a 'Grenade' item which explodes and hits everyone within 3 squares, then after the target location has been picked you'd just need to call GetPositionsInRadius with a radius of '3', then check all of those positions for fighters to injure.

So, to anyone who's been looking at the engine or thinking about using it - can you think of any other similar methods which might be useful? Would it be useful to have equivalent methods to those three which pick Fighters instead of Positions, for example?




...I also made a bit of a start painting a better version of the scrolling demo map, but that's going to take me a while at this rate... ;-)
scrolling-demo-wip-crop.jpg
scrolling demo rocks WiP
scrolling-demo-wip-crop.jpg (34.96 KiB) Viewed 818 times
Server error: user 'Jake' not found

User avatar
DaFool
Lemma-Class Veteran
Posts: 4171
Joined: Tue Aug 01, 2006 12:39 pm
Contact:

Re: Battle Engine - Alpha 4 release, downloads in first post

#233 Post by DaFool » Wed Oct 13, 2010 6:23 am

Is there a way to manually select the character you want to move (like an RTS) instead of cycling through a menu? I'm assuming it would use the same position tracker system when you're targeting enemies (but with range set to infinity). I want to minimize my menus and have all actions be context-based and clear the HUD from most clutter.

Also, I'm using SimpleTurnSchema but the player actions are still sequential depending on their initiative points. Is there a way to further break down the actions so that there is a clear 'Player Phase' and 'Enemy Phase', with the initiative (or Action Points?) shared among the members of each team. This makes it possible to select, move, and perform an action with a single character repeatedly in one turn as long as there is still Team AP left unconsumed. In addition, an 'End Turn' option will be present just in case the player is satisfied with the actions despite not consuming all the points. Later on, I can set it so that the Team AP consumption is doubled for every repeated action, thus discouraging players from reusing the same strategic characters (while not totally closing the option).

User avatar
Jake
Support Hero
Posts: 3826
Joined: Sat Jun 17, 2006 7:28 pm
Contact:

Re: Battle Engine - Alpha 4 release, downloads in first post

#234 Post by Jake » Wed Oct 13, 2010 7:49 am

These are the kind of things which should really be implemented as extensions replacing bits of the functionality provided by the defaults, which you can generally do by creating a subclass of the bit of the engine which would have normally performed the function in question and then making use of it via CustomSchema.
DaFool wrote:Is there a way to manually select the character you want to move (like an RTS) instead of cycling through a menu?
If you want to change the way the UI works, then the 'proper' way to do it is to create a new UIProvider class (the default one can be found in engine-display.rpy, IIRC). You really just need to subclass the existing one and replace the method that you want a new version of. I'm not sure of all the names off the top of my head, but it's something along the lines of:

Code: Select all

  class myUIProvider (UIProvider):
    def PickFighter(self, fighters):
      return renpy.random.choice(fighters)
(only, you know, with some better method than picking a guy at random...!)



As it happens, though, I'm actually planning to provide an alternative UIProvider which replaces the menu-based selection with a click-on-a-guy-to-select-him-based selection, so if you can wait a little you might be happy with my code for that.
DaFool wrote: Also, I'm using SimpleTurnSchema but the player actions are still sequential depending on their initiative points. Is there a way to
Again - you probably actually should create a new BattleMechanic class (IIRC the class name), which is the class responsible for running the turn sequence and deciding who goes when and how. Like that, you can sort and step through the Fighters in whatever order you like... again, looking at the existing examples - which I think are in engine-schema.rpy off the top of my head - should hopefully give you enough in the way of examples to work with.


(I might spend some time at lunch today implementing a skeletal version of these, if I have time; I was going to work on a pretend card-counter wargame for a hexmap demo, but this would probably be more interesting. ;-)
Server error: user 'Jake' not found

User avatar
Jake
Support Hero
Posts: 3826
Joined: Sat Jun 17, 2006 7:28 pm
Contact:

Re: Battle Engine - Alpha 4 release, downloads in first post

#235 Post by Jake » Wed Oct 13, 2010 5:00 pm

ADVANCED TOPIC: EXTENDING THE BATTLE ENGINE

OK! In response to DaFool's request above, I took the opportunity to write a couple of demonstrations of how to go about extending the battle engine to do more-game-specific stuff by writing your own classes that slot into the engine and provide particular chunks of functionality. I've taken pains at each step of writing the engine to make it as extensible as reasonably possible, and to allow a moderately-skilled OO programmer to be able to switch out more or less any part of the engine for a bit he wrote himself, so it can provide a framework that makes developing any kind of turn-based battle more easy. But of course 'more easy' isn't always the same as 'easy', and extending the engine in ways that I haven't thought of previously requires a bit more work than just setting up the building-blocks that I've provided.

The file attached will be included in subsequent releases as an example of how to extend the engine, possibly with a few more extensions of different chunks of functionality when I have the time. There's two classes defined in this file at the moment: AlternateUIProvider and AlternateBattleMechanic.



AlternateUIProvider is a subclass of UIProvider, found in engine-display.rpy. In this case we're just overriding one of UIProvider's methods, to change the behaviour when the user is picking a fighter for non-targetting purposes, e.g. when selecting which of his fighters to use next in a SimpleTurnSchema-driven battle.
The UIProvider class is responsible for all the necessary UI functions of the battle engine; whenever there's a need to pick a target enemy, or to choose a position to walk to - or anything else which requires user interaction to advance the battle - a relevant method on the UIProvider is called to... well, provide the UI. By extending this class you can change the user interface to look or behave however you want. If you don't want to have any user interaction at all, and want a game that plays itself (badly), you could just replace each method with one which picks an option at random, for example.

To use AlternateUIProvider in your battle, then use the 'CustomSchema' schema to override the UIProvider of an existing schema to use the new one. For example, to use it in the Isometric Grid Demo (where I test all my new features ;-) you should change line 160 of grid-demo.rpy to read:

Code: Select all

        schema = CustomSchema(SimpleTurnSchema, attackResolver=ElementalAttackResolver, uiProvider=AlternateUIProvider)


AlternateBattleMechanic is a subclass of BattleMechanic, found in engine-schema.rpy. Here we're changing the way a single turn of the battle plays out. Every round of the battle, the BattleMechanic's 'RunBattleRound' method is called to choose which fighters to allow to act, and in what order (basically, it's responsible for calling the 'RunFighterTurn' on the same class a number of times, passing in fighters in whatever order it wants)... in this case, we've changed the RunBattleRound method to go through each faction in turn, and for each faction, run through all fighters in descending order of 'Initiative' stat.

(There's a caveat in alpha 4 that, when using AlternateBattleMechanic, you have to be absolutely sure to have defined an 'Initiative' stat on each of the fighters when you first create them, otherwise it might break. I'm expanding the classes governed by the schema in alpha 5, so in the future this class will change a little and that stat will be defaulted if necessary.)

To use AlternateBattleMechanic in your battle, then use the 'CustomSchema' schema to override the mechanic of an existing schema to use the new one. For example, to use it in the Isometric Grid Demo you should change line 160 of grid-demo.rpy to read:

Code: Select all

        schema = CustomSchema(SimpleTurnSchema, attackResolver=ElementalAttackResolver, mechanic=AlternateBattleMechanic)
Attachments
extension-demo.rpy
Demo of extending the battle functionality by writing your own classes
(6.25 KiB) Downloaded 14 times
Server error: user 'Jake' not found

User avatar
DaFool
Lemma-Class Veteran
Posts: 4171
Joined: Tue Aug 01, 2006 12:39 pm
Contact:

Re: Battle Engine - Alpha 4 release, downloads in first post

#236 Post by DaFool » Thu Oct 14, 2010 12:40 pm

That was most helpful, I got the gameflow mechanics to just the way I like it, thanks.

Now all that's left is adjusting the HUD and UI. With dozens of characters on the field, it doesn't make sense to use ActiveDisplay or GridStatsDisplay since both of those functions cycle through the entire roster then append stats like crazy, filling up the entire screen.

Instead, I would like to modify CurrentFighterPointerEffect to show micro health bars hovering over player or enemy units. I'm not sure what sort of parameter to pass to it, since I need the flexibility to show health bars (as a function of a/b) as well as general status upgrades or ailments such as shield symbol to show a visual cue after modifying parameters with fighter.RegisterStat. I'm not even sure what parameter to pass to the Effects extra.

User avatar
Jake
Support Hero
Posts: 3826
Joined: Sat Jun 17, 2006 7:28 pm
Contact:

Re: Battle Engine - Alpha 4 release, downloads in first post

#237 Post by Jake » Thu Oct 14, 2010 2:37 pm

DaFool wrote: Instead, I would like to modify CurrentFighterPointerEffect to show micro health bars hovering over player or enemy units.
First of all - the current-fighter pointer is made up of two parts: CurrentFighterPointer (engine-extras line 412) and CurrentFighterPointerEffect (engine-extras line 454). The first of these is an Extra, which is a thing that can be added to a battle to modify or add something (as in RPGDamage, etc.), and the second one is an Effect, which is something which is added to a single Fighter for part or all of a battle to modify or add something to that fighter.

(Line numbers may be a bit off 'cause I'm just referring to my current working copy at the moment, and I think I made a couple of small changes in that file. But thereabouts. ;-)

So if I were to do something like you're talking about, I'd create an Effect that shows the health bars (since Effects are automatically re-drawn when a fighter redraws for whatever reason, and have the same Transforms applied to them), and then either apply that to all fighters whenever they're added to a Battle, or create another class like CurrentFighterPointer to add the effect under certain circumstances.

If you want to know what methods you can implement in an Extra, check the prototypical version of the Extra on line 82 of engine-extras. Similarly if you want to know what's available on an Effect, the prototype can be found on line 432, or thereabouts. Both classes derive from BattleAware (engine-extras line 18), and you can implement any of the event methods defined on BattleAware in your Extra if you want to do something in that situation.)
DaFool wrote: I'm not sure what sort of parameter to pass to it, since I need the flexibility to show health bars (as a function of a/b) as well as general status upgrades or ailments such as shield symbol to show a visual cue after modifying parameters with fighter.RegisterStat. I'm not even sure what parameter to pass to the Effects extra.
Well, in your show-the-health-bars Effect you'll probably just want to implement the 'Show' method, which has these parameters:

Code: Select all

    def Show(self, transforms=[], layer=None, zorder=None):
Take a look at the current-fighter pointer Effect to see how to descend from the class, you should be able to do it in one of your own init python blocks fine. You can reference "self._fighter" from within that method to get at the Fighter which the Effect has been applied to, so you can look up the stats from there.
Every fighter has three sets of stats - 'Stats' (the current values of all his stats, as modified by equipment etc.), 'BaseStats' (the 'untouched' value of each stat - whatever it was first set to - modified by equipment etc.) and 'RawStats' (the current values of all his stats, unmodified by equipment). So I guess you probably want to draw your healthbar by using BaseStats.Health and Stats.Health:

Code: Select all

  maxHealth = fighter.BaseStats.Health
  currentHealth = fighter.Stats.Health
  barWidth = ((float)currentHealth/(float)maxHealth) * maxBarWidth


Similarly, other stats can be looked up by looking at the property fighter.Stats.StatName or fighter.BaseStats.StatName or whatever.

Is that enough to get on with for now?
Server error: user 'Jake' not found

User avatar
DaFool
Lemma-Class Veteran
Posts: 4171
Joined: Tue Aug 01, 2006 12:39 pm
Contact:

Re: Battle Engine - Alpha 4 release, downloads in first post

#238 Post by DaFool » Fri Oct 15, 2010 5:18 pm

I am sort of starting to get it, but I still have no clue as to what sort of parameter an 'Effect' is. (Correct me if I'm wrong, there hasn't been a demonstration of temporary effects such as 'Poison', etc., only 'Charmed' which is more of a Skill)

Before I make my own AlternateCurrentFighterPointer, I first test the default one:

Code: Select all

        battle.AddExtra(CurrentFighterPointer(offset=(0, -75)))
gives

Code: Select all

TypeError: __init__() takes exactly 3 non-keyword arguments (1 given)
Do I pass the name of a fighter, a graphic, or a status which I have to declare in its own class?

I just need a little bit more hand-holding. Let's say, to keep things simple, I have a displayable called "mushroom" which is overlayed on top of the sprite of a poisoned unit. I know that the effect of poison is

Code: Select all

  fighter.Stats.Health = fighter.Stats.Health - poisondamage
before ending a fighter's turn.

I just need to know where to start in the sequence of declarations.

...Or let's start with something really, really simple... like a graphic of a smileyface which must be overlayed on top of all the sprites. Where exactly does the 'showing' of the graphic occur. How do you set it up? The reason I'm confused is because there are so many ui interface formatting interspersed throughout I'm not exactly sure where I can be free to declare a new screen or show a graphic.

User avatar
DaFool
Lemma-Class Veteran
Posts: 4171
Joined: Tue Aug 01, 2006 12:39 pm
Contact:

Re: Battle Engine - Alpha 4 release, downloads in first post

#239 Post by DaFool » Sat Oct 16, 2010 8:10 am

Gah, I should have tested this ages ago... I couldn't even overlay an explosion graphic.

Code: Select all

    class ColossalDeath(Extra):
                 
        def FighterDie(self, fighter):

            l = self._battle.GetLayer("Effects")              

            kbmbasic = 'gfx/kbmbase1.png'
            renpy.show(name="kaboom", at_list=[], what=kbmbasic, layer=l, zorder=1000)

#            renpy.transition(Dissolve(0.5), layer=l)
#            renpy.pause(0.8, hard=True)
            l = self._battle.GetLayer("Fighters")             
            # Hide fighter graphic
            renpy.hide(fighter.Tag, layer=l)
            renpy.transition(Dissolve(0.5), layer=l)
            renpy.pause(0.5, hard=True)
The game continues but with the error
Image 'gfx/kbmbase1.png' not found

The graphic is right there, though, I don't get it.

User avatar
Jake
Support Hero
Posts: 3826
Joined: Sat Jun 17, 2006 7:28 pm
Contact:

Re: Battle Engine - Alpha 4 release, downloads in first post

#240 Post by Jake » Sat Oct 16, 2010 8:58 am

DaFool wrote:I am sort of starting to get it, but I still have no clue as to what sort of parameter an 'Effect' is.
I'm not sure I know what you're asking, here... what do you mean by 'parameter'? When I use the word, I mean "value which is passed to a function/method", but I don't see how that fits into the sentence...

An Effect is a thing that you add to or remove from a Fighter, which makes some change to that fighter for the duration of its application. If you check in CurrentFighterPointer you can see the way it's added to or removed from the fighter:

Code: Select all

  fighter.AddEffect("key", effectInstance)
  ...
  fighter.RemoveEffect("key")
The 'key' can be anything, it's just to distinguish it from other effects and allow you to later remove the same instance that you added. The effectInstance has to be an instance of the Effect class (or a subclass of the Effect class) which you will generally get by calling the initialiser on the Effect you created:

Code: Select all

  effectInstance = MyEffect(fighter, data, otherdata)
You have to supply at least the 'fighter' parameter, which is the fighter you're applying that effect to - the others are up to you - if you need any more information in your Effect (you probably don't, if you just want to display stat bars, since you can get them from the Fighter) then you'll need to pass it in here.

(As it goes, this is part of the API that I'm still not sure about, and I'm tempted to - in a later release - change Effect's constructor to not require a Fighter instance, or automatically apply an Effect when created. I'll try and make such changes in a minimal-impact way if I can.)
DaFool wrote: (Correct me if I'm wrong, there hasn't been a demonstration of temporary effects such as 'Poison', etc., only 'Charmed' which is more of a Skill)
There's a 'HasteEffect' at the bottom of engine-extras.rpy which doubles a fighter's Speed for the duration of the Effect.

Basically, if you look at the definition of BattleAware, Extra, and Effect, you'll see a load of methods defined - most of them with no body, meaning they don't presently do anything. If you re-define one of those methods (e.g. FighterStartTurn) with the same parameter list in your own class, then that version will be called instead - meaning you can write code which runs whenever that event happens (so you could write code which attacks the Fighter with X poison damage every time his turn starts).

DaFool wrote: Before I make my own AlternateCurrentFighterPointer, I first test the default one
...
Do I pass the name of a fighter, a graphic, or a status which I have to declare in its own class?
There should be two parameters - a Displayable which you want to use as a pointer, and a tuple of two values to use as an offset. But it seems that the code in there is old (pre-panning) and I'm not using it in any of the demos, so I didn't notice that I'd broken it when I did the panning changes. If you change the Show method of CurrentFighterPointerEffect (somewhere around line 463 of engine-extras.rpy) to the following,

Code: Select all

        def Show(self, transforms=[], layer=None, zorder=None):
            transforms = [self._fighter.Position.Transform]
            offset = Transform(xoffset = self._offset[0], yoffset=self._offset[1])
            transforms.append(offset)
            
            renpy.show(self._tag, what=self._disp, at_list=transforms, layer=self._battle.GetLayer("Effects"), zorder=zorder)
and line 301 (I think) of engine-fighters.rpy from:

Code: Select all

                self._battle.UnregisterForEvents(effect)
to

Code: Select all

                self._battle.UnregisterForEvents(name)
then it should work. (These fixes will be included in Alpha 5.)


Then you can use it in a battle with something like:

Code: Select all

        battle.AddExtra(CurrentFighterPointer(Image('gfx/pointer.png'), (0, -90)))
(I'll leave it in the active demo, I think, so I don't miss it again - thanks for the catch!)

DaFool wrote: ...Or let's start with something really, really simple... like a graphic of a smileyface which must be overlayed on top of all the sprites. Where exactly does the 'showing' of the graphic occur. How do you set it up? The reason I'm confused is because there are so many ui interface formatting interspersed throughout I'm not exactly sure where I can be free to declare a new screen or show a graphic.
OK, here's what I'd do:
  • Create a new Effect - this will be the thing which actually draws the smiley face.
    • On that Effect, create an __init__ method which takes three parameters: self, fighter and disp.
    • Copy the first line of the __init__ method of CurrentFighterPointerEffect - this will make sure that the base class setup with the fighter gets done properly.
    • Set a property on self to contain the disp - this is the graphic that we'll show when we want to draw the smiley face.
    • Create a method called 'Show', which takes parameters: (self, transforms=[], layer=None, zorder=None) - this is an override of a method on the Effect, so when the Effect gets drawn by the engine your Show method will get called. In this method, you can call renpy.show and pass in the graphic we stored in a property of self. Like the fighter-select UI, it's best to give it a unique tag, so pick self._fighter.Tag and add a "smiley face" string to it or something. use self._fighter.Position.Transform in your at-list (that's the Transform which describes the fighter's position on-screen) and use a zorder of (fighter.Position.Z + 1) to make sure it gets shown above the fighter.
  • Now we have the effect which will draw an arbitrary graphic over any fighter it's applied to, you'll need to add it to your fighters somehow. If you want it to show up all the time, then you could just create an instance of it for each fighter and add it to that fighter when you first create the fighters and add them to the battle - like that, they'll have the effect all the time.
  • If you want to just show the smiley face when it's their turn, then you'll need to also create an Extra, which will be in charge of adding and removing the Effect when appropriate, and add that to your battle. To do this, you'll basically want to copy CurrentFighterPointer, which does a similar thing, only you wouldn't need the offset - it's hooking into FighterStartTurn and FighterEndTurn to add and remove the Effect from whichever fighter's turn is starting or ending.


Alternatively, I was going to do generic stat-bar support at some point (it's one of the features that the original Abraxas demo had, even!) so if you can hang on a bit you'll get it for free. If you don't have any luck making your own and it's something you're waiting on, I can move it up the priority queue a bit.




DaFool wrote:

Code: Select all

            kbmbasic = 'gfx/kbmbase1.png'
            renpy.show(name="kaboom", at_list=[], what=kbmbasic, layer=l, zorder=1000)
This is a Ren'Py thing - basically, there's three ways to specify a graphic: with a path to the graphic itself, with a Ren'Py-defined Image (as in "image eileen happy = "e_happy.png") or with a Displayable, which is a class Ren'Py uses internally to keep track of anything that can be displayed.

If you pass something to renpy.show, then it has to be a Displayable or the string name of a Ren'Py-defined image. So if you'd previously done "image explosion = 'gfx/kbmbase1.png' ", then you could pass what='explosion' into renpy.show... but as it is, you're telling it to look for an image which was previously defined in Ren'Py script with the name "gfx/kbmbase1.png" - so it's not looking for a graphic in your game directory, it's looking in Ren'Py's list of defined images.

You can define it previously (which is what I do in assets.rpy in the demos) or you can create an Image instance (a Displayable) passing in the path to load the image from a file:

Code: Select all

            kbmbasic = Image('gfx/kbmbase1.png')
            renpy.show(name="kaboom", at_list=[], what=kbmbasic, layer=l, zorder=1000)
Server error: user 'Jake' not found

Post Reply

Who is online

Users browsing this forum: No registered users