BEASTS ago-go

A forum to share your demonstrations stacks, fun stacks, games, etc.
User avatar
richmond62
Posts: 2883
Joined: Sun Sep 12, 2021 11:03 am
Location: Bulgaria
Contact:

BEASTS ago-go

Post by richmond62 »

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:
-
Screenshot 2024-02-13 at 21.20.07.png
Screenshot 2024-02-13 at 21.20.07.png (209.37 KiB) Viewed 437 times
-
Make a map in the way you want:
-
wesnothMapEditor.jpg
wesnothMapEditor.jpg (364.38 KiB) Viewed 434 times
-
Take a screenshot of your map:
-
screenshotOfWMEditor.jpg
screenshotOfWMEditor.jpg (386.48 KiB) Viewed 433 times
https://richmondmathewson.owlstown.net/
User avatar
richmond62
Posts: 2883
Joined: Sun Sep 12, 2021 11:03 am
Location: Bulgaria
Contact:

Re: BEASTS ago-go

Post by richmond62 »

Open your screen shot map in GIMP (a wonderful, Open Source image editor):

https://www.gimp.org/:
-
inGIMP.jpg
inGIMP.jpg (515.04 KiB) Viewed 433 times
-
Use GIMP to prepare a mask:
-
mask_1.jpg
mask_1.jpg (758.53 KiB) Viewed 431 times
-
mask_2.jpg
mask_2.jpg (317.87 KiB) Viewed 430 times
https://richmondmathewson.owlstown.net/
User avatar
richmond62
Posts: 2883
Joined: Sun Sep 12, 2021 11:03 am
Location: Bulgaria
Contact:

Re: BEASTS ago-go

Post by richmond62 »

Use GIMP to prepare a mask:
-
mask_3.jpg
mask_3.jpg (255.66 KiB) Viewed 429 times
-
mask_4.jpg
mask_4.jpg (291.66 KiB) Viewed 428 times
-
https://richmondmathewson.owlstown.net/
User avatar
richmond62
Posts: 2883
Joined: Sun Sep 12, 2021 11:03 am
Location: Bulgaria
Contact:

Re: BEASTS ago-go

Post by richmond62 »

Start up OXT Lite and make a new stack that is bigger than your Map image:
-
newStack.jpg
newStack.jpg (141.87 KiB) Viewed 427 times
-
Import your mask image:
-
importIMAGE.jpg
importIMAGE.jpg (121.12 KiB) Viewed 426 times
-
maskIMPORT.jpg
maskIMPORT.jpg (149.98 KiB) Viewed 425 times
-
SAVE your stack!
https://richmondmathewson.owlstown.net/
User avatar
richmond62
Posts: 2883
Joined: Sun Sep 12, 2021 11:03 am
Location: Bulgaria
Contact:

Re: BEASTS ago-go

Post by richmond62 »

Import your map image:
-
mapIMPORT.jpg
mapIMPORT.jpg (455.18 KiB) Viewed 423 times
-
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:
-
layers.jpg
layers.jpg (420.31 KiB) Viewed 422 times
-
SAVE your stack.
https://richmondmathewson.owlstown.net/
User avatar
richmond62
Posts: 2883
Joined: Sun Sep 12, 2021 11:03 am
Location: Bulgaria
Contact:

Re: BEASTS ago-go

Post by richmond62 »

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. 8-)

These images have been scaled and named sequentially:
-
craftPixIMPORT.jpg
craftPixIMPORT.jpg (383.46 KiB) Viewed 420 times
-
Attachments
MONSTER MASH_1.oxtstack.zip
(2.01 MiB) Downloaded 29 times
https://richmondmathewson.owlstown.net/
User avatar
richmond62
Posts: 2883
Joined: Sun Sep 12, 2021 11:03 am
Location: Bulgaria
Contact:

Re: BEASTS ago-go

Post by richmond62 »

Now let's look at character animation:
-
animation_1.jpg
animation_1.jpg (148 KiB) Viewed 411 times
-
This stack has been simplifed so we can concentrate on animating a sprite.

We need to create a rectangular graphic on our card:
-
animation_2.jpg
animation_2.jpg (194.17 KiB) Viewed 410 times
Attachments
ANIMATION 1_1.oxtstack.zip
(394.95 KiB) Downloaded 30 times
https://richmondmathewson.owlstown.net/
User avatar
richmond62
Posts: 2883
Joined: Sun Sep 12, 2021 11:03 am
Location: Bulgaria
Contact:

Re: BEASTS ago-go

Post by richmond62 »

Now you need to rename your rectangular graphic to "FRAME"
-
animation_3.jpg
animation_3.jpg (171.27 KiB) Viewed 408 times
-
and make 2 buttons:
-
animation_4.jpg
animation_4.jpg (154.45 KiB) Viewed 407 times
-
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/
User avatar
richmond62
Posts: 2883
Joined: Sun Sep 12, 2021 11:03 am
Location: Bulgaria
Contact:

Re: BEASTS ago-go

Post by richmond62 »

Here is a script that animates the monster to walk to the right:

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
-
animation_5.jpg
animation_5.jpg (159.85 KiB) Viewed 403 times
-
animation_6.jpg
animation_6.jpg (104.09 KiB) Viewed 402 times
-
NOW you should work out the script for the Left facing animation.
Attachments
ANIMATION 1_2.oxtstack.zip
(395.45 KiB) Downloaded 30 times
https://richmondmathewson.owlstown.net/
User avatar
richmond62
Posts: 2883
Joined: Sun Sep 12, 2021 11:03 am
Location: Bulgaria
Contact:

Re: BEASTS ago-go

Post by richmond62 »

NOW we need to look at knowing where a user clicks, and using a mask:
-
masks_1.jpg
masks_1.jpg (84.76 KiB) Viewed 398 times
-
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
as you can see, this is very simple.
Attachments
masks_1.oxtstack.zip
(1.62 MiB) Downloaded 26 times
https://richmondmathewson.owlstown.net/
User avatar
richmond62
Posts: 2883
Joined: Sun Sep 12, 2021 11:03 am
Location: Bulgaria
Contact:

Re: BEASTS ago-go

Post by richmond62 »

To detect a mask image we need to use the INTERSECT command, so we need to have another image that tracks the mouseLoc:
-
masks_2.jpg
masks_2.jpg (226.53 KiB) Viewed 395 times
-
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
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.
-
Attachments
masks_2.oxtstack.zip
(1.62 MiB) Downloaded 26 times
https://richmondmathewson.owlstown.net/
User avatar
richmond62
Posts: 2883
Joined: Sun Sep 12, 2021 11:03 am
Location: Bulgaria
Contact:

Re: BEASTS ago-go

Post by richmond62 »

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. 8-)
-
game.jpg
game.jpg (40.6 KiB) Viewed 369 times
https://richmondmathewson.owlstown.net/
User avatar
richmond62
Posts: 2883
Joined: Sun Sep 12, 2021 11:03 am
Location: Bulgaria
Contact:

Re: BEASTS ago-go

Post by richmond62 »

Here is the LEFT FACING animation script:
-
SShot 2024-02-15 at 15.40.15.png
SShot 2024-02-15 at 15.40.15.png (122.5 KiB) Viewed 368 times
-
Attachments
ANIMATION 1_3.oxtstack.zip
(395.49 KiB) Downloaded 28 times
https://richmondmathewson.owlstown.net/
xAction
Posts: 285
Joined: Thu Sep 16, 2021 1:40 pm
Contact:

Re: BEASTS ago-go

Post by xAction »

I did a little work,
ANIMATION 1_Plus_KeyboardControl_GameLoopv2.oxtStack
(415.34 KiB) Downloaded 30 times
Move with W A S D keys, One press = a complete turn of animated walking

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:
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
Animate.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
Turn.Complete
add 1 to gCurrentTurn
put true into bFinishTurn
It's hard to comment clearer than that.

Turn.RefreshUI
This one is even simpler
put "Turn:" && gCurrentTurn into field "CurrentTurn"
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 on

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.
xAction
Posts: 285
Joined: Thu Sep 16, 2021 1:40 pm
Contact:

Re: BEASTS ago-go

Post by xAction »

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

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
During the game
Game.Loop will trigger Player.Turn
Player.Turn will trigger Animate.Sprite
Animate.Sprite will trigger

Sprite.UpdateInTurn
put the SpriteDirection of me into gSpriteDirection
Sprite.Animate gSpriteDirection
Sprite.Move
Sprite.Animate is simply:
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.
User avatar
richmond62
Posts: 2883
Joined: Sun Sep 12, 2021 11:03 am
Location: Bulgaria
Contact:

Re: BEASTS ago-go

Post by richmond62 »

Can you upload your stack here so that we can play with it?
https://richmondmathewson.owlstown.net/
xAction
Posts: 285
Joined: Thu Sep 16, 2021 1:40 pm
Contact:

Re: BEASTS ago-go

Post by xAction »

User avatar
OpenXTalkPaul
Posts: 1679
Joined: Sat Sep 11, 2021 4:19 pm
Contact:

Re: BEASTS ago-go

Post by OpenXTalkPaul »

I converted to a group object with 2 animated gif for the run Sprites
SpriteGIFGroupMoving.oxtstack
(77.45 KiB) Downloaded 31 times
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.
User avatar
richmond62
Posts: 2883
Joined: Sun Sep 12, 2021 11:03 am
Location: Bulgaria
Contact:

Re: BEASTS ago-go

Post by richmond62 »

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/
User avatar
OpenXTalkPaul
Posts: 1679
Joined: Sat Sep 11, 2021 4:19 pm
Contact:

Re: BEASTS ago-go

Post by OpenXTalkPaul »

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.
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.

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
With currentFrame and framecount, you can manually iterate over the frames, set image control to show whatever cel/frame of the GIF you want.

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
moveSpeed - distance in pixels to move the object / per second
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 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).
set the repeatRate to xxx milliseconds
-- 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).
Post Reply

Who is online

Users browsing this forum: No registered users and 3 guests