BEASTS ago-go
- richmond62
- Posts: 4833
- Joined: Sun Sep 12, 2021 11:03 am
- Location: Bulgaria
- Contact:
BEASTS ago-go
For this exercise I shall start off by downloading Battle for Wesnoth (an Open Source game):
https://www.wesnoth.org/
I shall be using the MAP EDITOR to prepare several background images:
- -
Make a map in the way you want:
- -
Take a screenshot of your map:
-
https://www.wesnoth.org/
I shall be using the MAP EDITOR to prepare several background images:
- -
Make a map in the way you want:
- -
Take a screenshot of your map:
-
https://richmondmathewson.owlstown.net/
- richmond62
- Posts: 4833
- Joined: Sun Sep 12, 2021 11:03 am
- Location: Bulgaria
- Contact:
Re: BEASTS ago-go
Open your screen shot map in GIMP (a wonderful, Open Source image editor):
https://www.gimp.org/:
- -
Use GIMP to prepare a mask:
- -
https://www.gimp.org/:
- -
Use GIMP to prepare a mask:
- -
https://richmondmathewson.owlstown.net/
- richmond62
- Posts: 4833
- Joined: Sun Sep 12, 2021 11:03 am
- Location: Bulgaria
- Contact:
- richmond62
- Posts: 4833
- Joined: Sun Sep 12, 2021 11:03 am
- Location: Bulgaria
- Contact:
Re: BEASTS ago-go
Start up OXT Lite and make a new stack that is bigger than your Map image:
- -
Import your mask image:
- - -
SAVE your stack!
- -
Import your mask image:
- - -
SAVE your stack!
https://richmondmathewson.owlstown.net/
- richmond62
- Posts: 4833
- Joined: Sun Sep 12, 2021 11:03 am
- Location: Bulgaria
- Contact:
Re: BEASTS ago-go
Import your map image:
- -
Make sure that your map image is called "map", and that your mask image is called "masque", and that image "map" is exactly in the same pace as image "masque" on a higher layer:
- -
SAVE your stack.
- -
Make sure that your map image is called "map", and that your mask image is called "masque", and that image "map" is exactly in the same pace as image "masque" on a higher layer:
- -
SAVE your stack.
https://richmondmathewson.owlstown.net/
- richmond62
- Posts: 4833
- Joined: Sun Sep 12, 2021 11:03 am
- Location: Bulgaria
- Contact:
Re: BEASTS ago-go
To speed things up I have already import a sequence of images from CraftPix:
https://craftpix.net/freebies/
CraftPix is a tremendous resource, and they very generously offer many sprite sets absolutely free.
These images have been scaled and named sequentially:
- -
https://craftpix.net/freebies/
CraftPix is a tremendous resource, and they very generously offer many sprite sets absolutely free.

These images have been scaled and named sequentially:
- -
- Attachments
-
- MONSTER MASH_1.oxtstack.zip
- (2.01 MiB) Downloaded 109 times
https://richmondmathewson.owlstown.net/
- richmond62
- Posts: 4833
- Joined: Sun Sep 12, 2021 11:03 am
- Location: Bulgaria
- Contact:
Re: BEASTS ago-go
Now let's look at character animation:
- -
This stack has been simplifed so we can concentrate on animating a sprite.
We need to create a rectangular graphic on our card:
-
- -
This stack has been simplifed so we can concentrate on animating a sprite.
We need to create a rectangular graphic on our card:
-
- Attachments
-
- ANIMATION 1_1.oxtstack.zip
- (394.95 KiB) Downloaded 107 times
https://richmondmathewson.owlstown.net/
- richmond62
- Posts: 4833
- Joined: Sun Sep 12, 2021 11:03 am
- Location: Bulgaria
- Contact:
Re: BEASTS ago-go
Now you need to rename your rectangular graphic to "FRAME"
- -
and make 2 buttons:
- -
Now examine the sprite images at the bottom of the card: you will see that they are all called "crow" followed by either 'L' or 'R', and a number between 0 and 9.
This means that we can set them as the backGroundPattern of the graphic "FRAME" quite easily.
We can LOOP through these images to create movement.
- -
and make 2 buttons:
- -
Now examine the sprite images at the bottom of the card: you will see that they are all called "crow" followed by either 'L' or 'R', and a number between 0 and 9.
This means that we can set them as the backGroundPattern of the graphic "FRAME" quite easily.
We can LOOP through these images to create movement.
https://richmondmathewson.owlstown.net/
- richmond62
- Posts: 4833
- Joined: Sun Sep 12, 2021 11:03 am
- Location: Bulgaria
- Contact:
Re: BEASTS ago-go
Here is a script that animates the monster to walk to the right:
-
-
-
NOW you should work out the script for the Left facing animation.
Code: Select all
on mouseUp
put 0 into SPRITE
repeat until SPRITE > 9
put "crowR" & SPRITE into SNAME
set the backGroundPattern of graphic "FRAME" to the ID of image SNAME
wait 10 ticks
add 1 to SPRITE
end repeat
end mouseUp
NOW you should work out the script for the Left facing animation.
- Attachments
-
- ANIMATION 1_2.oxtstack.zip
- (395.45 KiB) Downloaded 110 times
https://richmondmathewson.owlstown.net/
- richmond62
- Posts: 4833
- Joined: Sun Sep 12, 2021 11:03 am
- Location: Bulgaria
- Contact:
Re: BEASTS ago-go
NOW we need to look at knowing where a user clicks, and using a mask:
- -
The image "map" contains a script to detect where a user clicks, and that location is put into the field "OUTPUT":
as you can see, this is very simple.
- -
The image "map" contains a script to detect where a user clicks, and that location is put into the field "OUTPUT":
Code: Select all
on mouseUp
put the mouseLoc into field "OUTPUT"
end mouseUp
- Attachments
-
- masks_1.oxtstack.zip
- (1.62 MiB) Downloaded 101 times
https://richmondmathewson.owlstown.net/
- richmond62
- Posts: 4833
- Joined: Sun Sep 12, 2021 11:03 am
- Location: Bulgaria
- Contact:
Re: BEASTS ago-go
To detect a mask image we need to use the INTERSECT command, so we need to have another image that tracks the mouseLoc:
- -
In this stack I have made the image "map" partly transparent (so we can see where the image "masque" is), and made an image "blob" to track the mouseLoc.
In a fully developed game the transparency of the MAP image would be removed so that the MASK image is invisible, and the tracking image (image "blob") would be hidden on a lower layer than the MAP image.
Of course if one wanted an animated 'player' to move to the mouseLoc a tracking image would not be required.
-
- -
In this stack I have made the image "map" partly transparent (so we can see where the image "masque" is), and made an image "blob" to track the mouseLoc.
Code: Select all
on mouseUp
set the location of image "blob" to the mouseLoc
if intersect(image "masque", image "blob", 5) then
put "MASK" into field "OUTPUT2"
else
put "SAFE" into field "OUTPUT2"
end if
put the mouseLoc into field "OUTPUT"
end mouseUp
Of course if one wanted an animated 'player' to move to the mouseLoc a tracking image would not be required.
-
- Attachments
-
- masks_2.oxtstack.zip
- (1.62 MiB) Downloaded 104 times
https://richmondmathewson.owlstown.net/
- richmond62
- Posts: 4833
- Joined: Sun Sep 12, 2021 11:03 am
- Location: Bulgaria
- Contact:
Re: BEASTS ago-go
I will continue this thread next week (other things have cropped up): if you are following the thread please make sure you understand everything BEFORE the next stage.
AND, if you have any questions, Ask them HERE.
-
AND, if you have any questions, Ask them HERE.

-
https://richmondmathewson.owlstown.net/
- richmond62
- Posts: 4833
- Joined: Sun Sep 12, 2021 11:03 am
- Location: Bulgaria
- Contact:
Re: BEASTS ago-go
Here is the LEFT FACING animation script:
- -
- -
- Attachments
-
- ANIMATION 1_3.oxtstack.zip
- (395.49 KiB) Downloaded 106 times
https://richmondmathewson.owlstown.net/
-
- Posts: 285
- Joined: Thu Sep 16, 2021 1:40 pm
- Contact:
Re: BEASTS ago-go
I did a little work,
Added Field "StatusField" to the top right corner.
That is updated at every handler and function
So if something hangs there is an indicator of what was called last
Hmm, every handler and function of the stack script at least.
Might have to do more work...anyway
Added openCard handler to card script to call init.App
New globals in stack script:
New functions and handlers in stack script
Turn.RefreshUI
This one is even simpler
math.InflateObjectRect --- breaks down the rect of an object for math.inflatedRect to digest
stackFunctionHandlerList --- list all these functions in the comfort of your very own home.
I'll post this before i break it while trying to comment on it, and Then I'll post about the Sprite Object Script after I eat.
Move with W A S D keys, One press = a complete turn of animated walkingAdded Field "StatusField" to the top right corner.
That is updated at every handler and function
So if something hangs there is an indicator of what was called last
Hmm, every handler and function of the stack script at least.
Might have to do more work...anyway
Added openCard handler to card script to call init.App
New globals in stack script:
global bAppinit --- have we run the inits of this app?
global bPlaying --- is the game running?
global bFinishTurn --- are all turn sequences run?
global gLastKeyDown --- what key was was pressed?
global gLastKeyUp --- was the last key released?
global gMoveX --- direction modifier -1 , 0 or 1
global gMoveY --- direction modifier -1 , 0 or 1
global gGridSize--- number of pixels moved per turn, I think
global gEventText --- did something happen? A bug? Maybe?
global gCurrentTurn --- the current turn of the Game.Loop
global bAnimating --- everything finishes animating their sprite frames per turn before our game loop completes
global gAnimatingObjectLabel --- the name of the object that needs to be messaged Sprite.UpdateInTurn to finish it's animations before the turn can complete.
New functions and handlers in stack script
Turn.CompleteAnimate.Sprite tObjectName,tDirection
this will run a bunch of times each turn check to see if whatever object has animation frames needs to finish their loop
--- movement by key
rawKeyDown --- go in direction -1, 0, or 1 on X OR Y
rawKeyUp
init.App ---- the switch that turns everything on, well one of them
init.Game --- The game begins here.
init.Globals --- Everything that is and was and will be, probably should be named.
init.Sprite tName --- for now sets the named sprite at the center of the screen sets gMoveX,gMoveY and sends that along with gGridSize and the animation direction "left" or "right" to the object's Sprite.Init handler.
Game.loop ---- dizzy yet? All Turns Take Place In Loop
Game.validatePlaying --- Game.Loop is stopped unless validated by "pointer tool" and bAnimating being false. Animation happens a few cycles a turn.
Turn.Player --- reactions to input signal player's sprite from here
It's hard to comment clearer than that.add 1 to gCurrentTurn
put true into bFinishTurn
Turn.RefreshUI
This one is even simpler
math.inflatedRect --- you know how you have the glow around the buttons? this takes a rectangle and scales it by an insanely sensitive amount and gives you a new rect to detect collision onput "Turn:" && gCurrentTurn into field "CurrentTurn"
math.InflateObjectRect --- breaks down the rect of an object for math.inflatedRect to digest
stackFunctionHandlerList --- list all these functions in the comfort of your very own home.
I'll post this before i break it while trying to comment on it, and Then I'll post about the Sprite Object Script after I eat.
-
- Posts: 285
- Joined: Thu Sep 16, 2021 1:40 pm
- Contact:
Re: BEASTS ago-go
I've renamed your "FRAME" to "Player1" because we can control it now....although using the name of a UI control is killing me. This is all from the script of that "Player1"/"FRAME" sprite object.
At the start of the game it will get a message to
Sprite.Init
Game.Loop will trigger Player.Turn
Player.Turn will trigger Animate.Sprite
Animate.Sprite will trigger
Sprite.UpdateInTurn
Sprite.Move provides the movement over time.
You move in a direction -1 or 1 multiplied by the grid size divided by the number of frames to play.
The hot foot functionality responds to the inflated rect of 'glowing' buttons.
There is an invisible border at the top and a response to the 'ground' graphic below
There is a loop around effect in the X directions
Sprite.Move
When the animation has completed Sprite.FrameZero resets the sprite's globals while the rest of the game turn continues.
This is all just for show, scripts in the IDE is where you want to be.
At the start of the game it will get a message to
Sprite.Init
During the game
put 0 into SpriteFrame --- the current frame
put 9 into MaxFrames --- the number of frames available
--- custom properties are accessed by the stack script to detect status of the animation
set the FrameNumber of me to SpriteFrame
set the MaxFrameNumber of me to MaxFrames
--- we build a name based on the "crow" & it's direction & it's current frame
put "crow" & gSpriteDirection & SpriteFrame into SpriteName
--- set the sprite to the center of the stack
put width of this stack/2 into originX
put height of this stack /2 into originY
set the loc of me to originX,originY
--- copy the movement direction & grid size sent from Loop.Player into the object's script globals
put tMoveX into gMoveX
put tMoveY into gMoveY
put tGridSize into gGridSize
--- default to looking right?
put "Right" into gSpriteDirection
-- set the SpriteDirection custom property of the object because variables were giving me 'empty' grief.
set the SpriteDirection of me to gSpriteDirection
Game.Loop will trigger Player.Turn
Player.Turn will trigger Animate.Sprite
Animate.Sprite will trigger
Sprite.UpdateInTurn
Sprite.Animate is simply:put the SpriteDirection of me into gSpriteDirection
Sprite.Animate gSpriteDirection
Sprite.Move
Add 1 to SpriteFrame
if SpriteFrame > MaxFrames then put 0 into SpriteFrame
set the FrameNumber of me to SpriteFrame
put "crow" & char 1 of gSpriteDirection & SpriteFrame into SpriteName
set the backGroundPattern of me to the ID of image SpriteName
Sprite.Move provides the movement over time.
You move in a direction -1 or 1 multiplied by the grid size divided by the number of frames to play.
The hot foot functionality responds to the inflated rect of 'glowing' buttons.
There is an invisible border at the top and a response to the 'ground' graphic below
There is a loop around effect in the X directions
Sprite.Move
put the loc of me into spriteXY
put item 1 of spriteXY into x
put item 2 of spriteXY into y
--- hot foot!
put bottom of me into myBottom
put math.InflateObjectRect("button","LEFT FACING",3) into HotFootRect
if x,myBottom is within HotFootRect then subtract 4 from y
put math.InflateObjectRect("button","Right FACING",3) into HotFootRect
if x,myBottom is within HotFootRect then subtract 4 from y
--- change position maybe
add (gMoveX*gGridSize)/MaxFrames to x
add (gMoveY*gGridSize)/MaxFrames to y
--- react to ground graphic
if bottom of me > item 2 the loc of graphic "Ground" then
set the bottom of me to item 2 the loc of graphic "Ground"-1
put the loc of me into spriteXY
put item 2 of spriteXY into y
end if
--- borders and wrap around
if y - height of me < 0 then put item 2 of spriteXY into y
if y + height of me > height of this stack then put item 2 of spriteXY into y
if x < 0 then put width of this stack - (Width of me/1.5) into x
if x > width of this stack then put (Width of me/1.5) into x
--- set position of the object
set the loc of me to x,y
When the animation has completed Sprite.FrameZero resets the sprite's globals while the rest of the game turn continues.
put 0 into SpriteFrame
set the FrameNumber of me to SpriteFrame
This is all just for show, scripts in the IDE is where you want to be.
- richmond62
- Posts: 4833
- Joined: Sun Sep 12, 2021 11:03 am
- Location: Bulgaria
- Contact:
Re: BEASTS ago-go
Can you upload your stack here so that we can play with it?
https://richmondmathewson.owlstown.net/
-
- Posts: 285
- Joined: Thu Sep 16, 2021 1:40 pm
- Contact:
- OpenXTalkPaul
- Posts: 2633
- Joined: Sat Sep 11, 2021 4:19 pm
- Contact:
Re: BEASTS ago-go
I converted to a group object with 2 animated gif for the run Sprites
This is another demo stack that doesn't have a 'send in timer' runloop set up. The only thing it does is changes the idleRate (affects the mouseStillDowns) and the move speed (affects animation / visual effects). But 'Send in time' loop(s) is the better method for animating, it gives you more control to adjust timing for smoother animations, but I was only interested in working out the directional controls (for now).
I was going to use a single GIF and then flip it horizontally, however apparently 'Flip <image>' horizontal|vertical syntax is broken when used with multi-frame GIFs, it produces a single frame copy of the image data replacing the original and so you loose all other frames of an animated GIF, with no warning at all (it should offer a warning ), it just goes ahead and does it and you're left to try to figure out why your animation no longer plays.
This variation on sprite moving uses those buttons (hold down to keep walking or use Left/Right arrowkeys ) and has (rough) jumpRight / jumpLeft too, which can be triggered with the space bar. There's two animated GIF images in that group, one for left movement and one for right. The grouped control is set up like an Object Oriented Programming object, so you send it messages to make the group control do things (move & jump, so far). If Player1 walks off of one side of the card it reappears on the other side.
This is another demo stack that doesn't have a 'send in timer' runloop set up. The only thing it does is changes the idleRate (affects the mouseStillDowns) and the move speed (affects animation / visual effects). But 'Send in time' loop(s) is the better method for animating, it gives you more control to adjust timing for smoother animations, but I was only interested in working out the directional controls (for now).
I was going to use a single GIF and then flip it horizontally, however apparently 'Flip <image>' horizontal|vertical syntax is broken when used with multi-frame GIFs, it produces a single frame copy of the image data replacing the original and so you loose all other frames of an animated GIF, with no warning at all (it should offer a warning ), it just goes ahead and does it and you're left to try to figure out why your animation no longer plays.
- richmond62
- Posts: 4833
- Joined: Sun Sep 12, 2021 11:03 am
- Location: Bulgaria
- Contact:
Re: BEASTS ago-go
Personally I find there is less opportunity for fine-grained control with an animated GIF than with some sort of frame and a series of either GIF or PNG images.
https://richmondmathewson.owlstown.net/
- OpenXTalkPaul
- Posts: 2633
- Joined: Sat Sep 11, 2021 4:19 pm
- Contact:
Re: BEASTS ago-go
With Animated GIF you can have the same sort of fine grain control you can have over separate image files/pixel data in separate image controls. If you don't need fine control, like use cases where you just want a progress indicator or a spinner that animates on its own while your script does something else.richmond62 wrote: ↑Wed Feb 21, 2024 12:05 pm Personally I find there is less opportunity for fine-grained control with an animated GIF than with some sort of frame and a series of either GIF or PNG images.
PNG is fully 24bit color (RGB+Alpha so actually 32bits) and so it looks nicer, but there are actually a few other advantages to using Animated GIF over separate GIFs and GIF over PNG files too:
- Animated GIFs aren't separate, that's an advantage when it come to sprites. You want them together and in a certain visual / chronological order, you don't want a single frame to accidentally get deleted and suddenly your sprite's tough-guy walk is now a dandy skip! In my opinion it's just way more convenient to have all ani frames encapsulated in a single file.
- GIF format is NOT RGB, it's index color, which means you can change the colors of a GIF Frame AND every other frame that uses the same color table (often there's only one color table per file) by altering that color table, so for example you could change some colors of Player1's Sprite lets say Red, to make a Player2's sprite that's Blue from the same pixel data just by swapping the color table with another color table. If I remember correctly you can do that with OXT Engine using the 'set the colorMap to colorsList' to apply a color table, then copy the image data (or the image text) to make a permanent copy of the modified image. I was playing around with that sort of thing back when I started to check out 'Decker', since I needed images to have a 1980s MacII 16-color color table for that.
- GIF Format is smaller than PNG, sure it doesn't have good color fidelity but that index color version is a much smaller amount of data. It also supports lossless compression (and that's no longer patent hindered) and there is a version of the format that only stores updated regions for each consecutive frame from the previous frame (it can look like motion trails when they overlap).
Size of the data might not seem important when you only have a few frames you're animating, but I was just playing around with an Isometric Sprite set, where I have 20 frames of walk animations for 8 different directions. That would be 160 separate images (and the set actually includes 16 directions, but I didn't need all of that). I made a combined Animated GIF for each direction, so I had 8 image controls on my card instead of 160 or more. I haven't even added any of the other actions the sprite can do yet (jump, rest, kick, upper attack, etc.). With a GIF the 160 frames. all together are under 2Mb, vs. the original sprite sheets PNG file that I sliced them from that are way more data, more than 50MB!
- GIF is a simple chunk format (RIFF) container, and it's the older format designed for much harsher hardware limitations, compatible with much older computers (1980s). I can view an Animated GIF with just about anything, a browser, right in the Finder / File Mmanager, in a forum post , or email, etc.
I suppose you could use animated PNG (.APNG) format too. It was intended as a better (and patent free) alternative animated file format, but I don't think there is a lot of software supports that format because it was never truly embraced by the general public.
- Animated GIF allows for the engine to automatically cycle through the frames at steady intervals, you still have control with properties:
repeatcount says how many times the gif should loop the animation (natively, so to have it play once set the repeatcount to 1), to allow it to loop continuously set this to -1
framecount returns the number of frames in the GIF.
currentframe is the currently showing frame
Animated GIF will keep iterating through frames while you're moving it with the move command, without having to script that part.
Which is great if you just want to quickly test out an animation while syncing it to directional controller input, you can add finer control over some individual frame's rates later (you can even do that in a Animated GIF format using an external GIF Editor (I have some ideas about fixing that need for external app)
Code: Select all
set the repeatcount of image "imagename" to - 1 -- loop forever
move image "imagename" from the loc of image "imagename" to the loc of this card in 200 millliesocnds
-- stop looping:
set the repeatCount of image "imagename" to 0
set the currentFrame of image 1 to the framecount of image 1 -- display to last animation frame
Manually iterate currentframe:
Code: Select all
repeat with i = 1 to the framecount of image "imagename"
set the moveSpeed to 128 -- distance in pixels to move per second
set the currentframe of image 1 to i
wait 100 milliseconds with messages -- adjust this number as needed to get the frame rate desired
end repeat
And you can play around with judicially placed Lock Screen, lock moves, unlock screen, unlock moves moves to try to sync multiple moves / animations. I'm still trying to figure that out.
As far as general animation concerns, it seems that changing some other timing related Engine properties like idleRate can sometimes help or at least make some difference with timing issues.
set the repeatRate to xxx millisecondsset the idleRate to 500 -- one idle message per half second
-- The idleRate is an integer between zero and 65535.
-- By default, the idleRate property is set to 200 (one-fifth of a second).
-- for scrollbar buttons repeat rate
set the syncRate to tNumber - how often the display is updated during visual effect, drag, and move commands.
Decreasing the syncRate reduces the load on the system, but may make the display of movements and visual effects more jerky. Increasing the rate may help jerky movements (but increases the CPU load. The default value of syncRate is 20.
There's the effectRate property that specifies how long a very slow visual effect takes, but may effect other screen updating.
There's acceleratedRendering ad related properties, which may or may not use the GPU depending on the platform:
set the compositorType of this stack to "software" -- options are: none | software | coregraphics | OpenGL
set the acceleratedRendering of stack to true -- or false
set the compositorTileSize of stack to 128 -- 128x128 pixel tileSize
set the compositorCacheLimit of this stack to 8388608 -- 8Mb
Setting LayerMode to dynamic, scrolling or container may or may not help
set the layerMode of image "background" to "dynamic" -The object is dynamic and subject to change and/or movement.
Other options for layerMode are:
static - (default) The object is static and does not move or change.
scrolling - Applies to groups only and is used where the group contains contents to scroll. The group must be unadorned or the layerMode is set to 'dynamic' (no borders, no scrollbars).
container - Applies to groups only and is used where the group is intended only to organise or restrict the visible area of its contents. The group must be unadorned or the layerMode is set to 'dynamic' (no borders, no scrollbars).
Who is online
Users browsing this forum: No registered users and 2 guests