(Help) showing custom pictures with lua

Post here for help and support regarding LunaLua and SMBX2's libraries and features.
vee_Sleepy
Fighter Fly
Fighter Fly
Posts: 40
Joined: Tue Nov 29, 2022 7:15 pm
Flair: oh worm?
Pronouns: they/it

(Help) showing custom pictures with lua

Postby vee_Sleepy » Fri Dec 02, 2022 3:22 pm

hi! I'm a complete coding newbie in any language, so idk how to do basic stuff with luna.lua files on SMBX2

I was wondering how I can load custom images, manipulate them on screen (scale, fade, position) and use them with events to do things like having a slideshow opening cutscene or a boss health bar, etc.

if some part of that is a little too advanced to cover for me in a single thread, i do accept other guides and videos, generally being directed to how i can learn lua scripting. thanks in advance :3

Emral
Cute Yoshi Egg
Cute Yoshi Egg
Posts: 9720
Joined: Mon Jan 20, 2014 12:58 pm
Flair: Phoenix

Re: (Help) showing custom pictures with lua

Postby Emral » Fri Dec 02, 2022 8:20 pm

For simple drawing (no scale or rotation), the Graphics.drawImage family of functions will serve you well.
https://docs.codehaus.moe/#/reference/g ... -functions

Code: Select all

local img = Graphics.loadImage("fileName.png")

function onDraw()
	Graphics.drawImage(img, 0, 0)
end
For more advanced drawing, https://docs.codehaus.moe/#/reference/sprite

vee_Sleepy
Fighter Fly
Fighter Fly
Posts: 40
Joined: Tue Nov 29, 2022 7:15 pm
Flair: oh worm?
Pronouns: they/it

Re: (Help) showing custom pictures with lua

Postby vee_Sleepy » Sat Dec 03, 2022 5:56 am

okay... how do I go about erasing an image? what's the command there
i can at least figure that different images are stored as those local variables, so i'm not stuck with just one possible image

Emral
Cute Yoshi Egg
Cute Yoshi Egg
Posts: 9720
Joined: Mon Jan 20, 2014 12:58 pm
Flair: Phoenix

Re: (Help) showing custom pictures with lua

Postby Emral » Sat Dec 03, 2022 6:36 am

The learning curve is a bit steep because there aren't commands for everything. The computer thinks a bit differently than you or I, so it's important to translate your ideas into something this hunk of metal understands.
With regards to the above snippit: It loads the image at the top of the file. The top of the file is executed whenever the level loads, so you can be sure to have the image available in the variable named "img", as you correctly noted. Worth knowing is that calling the variable something else like "pictureOfMario" is just as valid! Variable names are there for you, the human, to make sense of the use you have for what is stored within.
Next, the "function onDraw" is a lunalua event (built-in function) which executes once every frame in-game, around the time when SMBX draws its gameplay elements to the screen. There are a lot more lunalua events (https://docs.codehaus.moe/#/reference/lunalua-events), but for now the important thing to note is: Graphics.drawImage, in the above code, doesn't permanently place an image on the screen, but instead renders it anew every frame.
So with regards to "erasing" it, what you need to tell the computer is "When should I draw it?" - this is what the common programming tool, the if statement, is for. Here's a slightly altered version of my example.

Code: Select all

local img = Graphics.loadImage("fileName.png")

local shouldDrawTheImage = false

function onDraw()
	if player.keys.down == KEYS_PRESSED then
		shouldDrawTheImage = not shouldDrawTheImage
	end
	if shouldDrawTheImage then
		Graphics.drawImage(img, 0, 0)
	end
end
This augmented example introduces a second variable: shouldDrawTheImage. It's a boolean (can be either false, or true. Think of it as flipping a light switch.). The Graphics.drawImage is now encapsulated (programming word meaning "within") an if statement which only runs its contents if that variable is true, not false. Directly above, another if statement is placed. This one toggles the variable. The if statement here is a bit much to take in, since it uses a lot of SMBX2 native jargon, but in essence: "player" is a pre-defined variable for the first player, keys.down is where you can read the current frame's value of the down directional button, and the comparison == KEYS_PRESSED checks if a tap on the button occurred.
To rephrase that: When player 1 presses down, the light switch's state is changed! On frames where it's ON (true) the image draws, otherwise not.
The big takeaway here is that the condition that causes the boolean to be toggled can be virtually anything. Using the onEvent lunalua event, you can make the image draw as soon as a SMBX event is triggered, for instance.

Code: Select all

local img = Graphics.loadImage("fileName.png")

local shouldDrawTheImage = false

function onDraw()
	if shouldDrawTheImage then
		Graphics.drawImage(img, 0, 0)
	end
end

function onEvent(eventName)
	if eventName == "P Switch - Start" then
		shouldDrawTheImage = not shouldDrawTheImage
	end
end
Now it shows the image when a P-Switch is pressed (and hides it when the next p-switch is pressed).

One last note: Since it all happens anew every frame, MOVING images follows the same principle: Using a variable whose state changes every frame, we can exchange the 0, 0 for the images X and Y coordinates with dynamic values. Here's a quick and dirty sine wave motion along the X axis:

Code: Select all

local img = Graphics.loadImage("fileName.png")

local timer = 0


function onDraw()
	timer = timer + 1
	local sineWavePosition = math.sin(timer/100) * 64
	Graphics.drawImage(img, sineWavePosition, 0)
end

vee_Sleepy
Fighter Fly
Fighter Fly
Posts: 40
Joined: Tue Nov 29, 2022 7:15 pm
Flair: oh worm?
Pronouns: they/it

Re: (Help) showing custom pictures with lua

Postby vee_Sleepy » Sat Dec 03, 2022 7:01 pm

thanks a bunch :0
i'll experiment with those, and other lua scripting, whenever i have the time... more accurately, whenever i have the motivation lol
stuff happens and the will to do things ends up rare sometimes, but that doesn't really matter here does it now
appreciate the detailed explanation!

Added in 6 hours 11 minutes 15 seconds:
i was gonna have one final question about only showing images in certain sections, like for a boss level, as one of my initial examples, but as i was writing it i realized "that can probably be achieved by tying the image being drawn to the boss events lmao" so i kinda answered myself-
oopsies

Added in 6 minutes 35 seconds:
i suppose the better question is how to tie the pictures to an npc's health value and said value going down, instead of... making some convoluted chain of events to use with the script

Emral
Cute Yoshi Egg
Cute Yoshi Egg
Posts: 9720
Joined: Mon Jan 20, 2014 12:58 pm
Flair: Phoenix

Re: (Help) showing custom pictures with lua

Postby Emral » Sun Dec 04, 2022 3:51 am

vee_Sleepy wrote:
Sun Dec 04, 2022 1:19 am
i was gonna have one final question about only showing images in certain sections, like for a boss level
This one is a similar application of the prior example.

Code: Select all

function onDraw()
  if player.section == 0 then
    -- code here only runs in the first section
  end
end
vee_Sleepy wrote:
Sun Dec 04, 2022 1:19 am
how to tie the pictures to an npc's health value and said value going down
This kind of depends on how the health image is set up. So like, whether you are using multiple images, a spritesheet, or a stack of images like in Mega Man.
Let's assume for this that the health of the boss is a data variable on the boss NPC, "data.health", which starts at 3 and goes down in steps of 1.
This following script sets that up, making goombas take 3 hits.

Code: Select all

function onNPCHarm(eventObj, npc, harmReason, culprit)
	if npc.id == 1 and harmReason ~= HARM_TYPE_VANISH then
		if npc.data.health == nil then
			npc.data.health = 3
		end
		
		npc.data.health = npc.data.health - 1
		if npc.data.health > 0 then
			eventObj.cancelled = true -- cancel the  NPC from taking damage if the health has not yet reached 0
		end
	end
end
If you are using multiple images, I recommend the following structure. This draws it to the NPC's location, as an example.

Code: Select all

local healthImages = {
	[1] = Graphics.loadImage("bossHas1HPImage.png"),
	[2] = Graphics.loadImage("bossHas2HPImage.png"),
	[3] = Graphics.loadImage("bossHas3HPImage.png")
}
function onDraw()
	for _,npc in NPC.iterate(1) do
		local health = npc.data.health or 3
		
		Graphics.drawImageToScene(healthImages[health], npc.x, npc.y)
	end
end
If you are using the spritesheet, you can instead use the 4th and 5th arguments of drawImage/ToScene (sourceX, sourceY) and the 6th and 7th (width, height) to define the region of the spritesheet to be drawn. Say they are stacked vertically, and each image on the sheet is 32 pixels wide and tall:

Code: Select all

local healthImage = Graphics.loadImage("bossHealth.png")
function onDraw()
	for _,npc in NPC.iterate(1) do
		local health = npc.data.health or 3
		
		Graphics.drawImageToScene(healthImage, npc.x, npc.y, 0, 32 * (health - 1), 32, 32)
	end
end
If you are drawing a mega man-like stack of images, you can use a for loop to draw the same image repeatedly at an offset.

Code: Select all

local healthImage = Graphics.loadImage("bossHealth.png")
function onDraw()
	for _,npc in NPC.iterate(1) do
		local health = npc.data.health or 3
		
		for i=1, health do
			Graphics.drawImageToScene(healthImage, npc.x, npc.y - 32 * i)
		end
	end
end
You can also draw a bar, though it gets a bit more complex because it's not something supported by the drawImage family of functions.
https://docs.codehaus.moe/#/reference/sprite#spritebar

vee_Sleepy
Fighter Fly
Fighter Fly
Posts: 40
Joined: Tue Nov 29, 2022 7:15 pm
Flair: oh worm?
Pronouns: they/it

Re: (Help) showing custom pictures with lua

Postby vee_Sleepy » Sun Dec 04, 2022 2:10 pm

the idea i had was using multiple images, but as a sort of segmented health bar where each time you land a hit one of the segments disappears
also in that first chunk of code that reads the NPC's health, i figure the first parenthesis bits have to be swapped out accordingly, right? like, inputting the NPC ID and all that

Emral
Cute Yoshi Egg
Cute Yoshi Egg
Posts: 9720
Joined: Mon Jan 20, 2014 12:58 pm
Flair: Phoenix

Re: (Help) showing custom pictures with lua

Postby Emral » Sun Dec 04, 2022 8:18 pm

vee_Sleepy wrote:
Sun Dec 04, 2022 2:10 pm
the idea i had was using multiple images, but as a sort of segmented health bar where each time you land a hit one of the segments disappears
Ahh, so that'd be like a variation of the last one I showed. It could even be combined with the first one, selecting which image to show based on the i of the inner for loop.
vee_Sleepy wrote:
Sun Dec 04, 2022 2:10 pm
also in that first chunk of code that reads the NPC's health, i figure the first parenthesis bits have to be swapped out accordingly, right? like, inputting the NPC ID and all that
Yep, that's exactly right. All the numbers are example values. The npc.id check for 1 checks for the SMB3 goomba specifically, because I didn't know what your boss would be. The HARM_TYPE_VANISH, however, is just a filter to stop the code from happening on despawn, and can be left as-is. https://docs.codehaus.moe/#/constants/enemy-harm-types
I should mention that for vanilla bosses, the rules are a bit different. Take Boom Boom, Bowser or Birdo. SMBX already keeps track of their health, but lunalua doesn't have variables to access them directly by name. So what we do for those is we access the point in the game's memory where it is stored. It looks a bit intimidating...

Code: Select all

local health = npc:mem(0x148, FIELD_FLOAT)
https://docs.codehaus.moe/#/reference/n ... ry-offsets

The tradeoff is that the onNPCHarm is no longer necessary, because SMBX already does the calculations. And in onDraw we can use the above line instead of accessing npc.data.health.

The funky thing about this variable is that it was originally programmed to count UP, and it is saved as a FLOAT (a decimal value). So for Boom Boom, the HP values are 0 when on full HP (ordinarily, and 9 when dead. He takes 1 damage from fireballs and 3 from a jump. And if using the "health" npc config flag, "full hp" is calculated as (dead hp [9] - health config [15, for example] = -6). If that is something you'll need to deal with and have further questions on, I can go into more detail.

vee_Sleepy
Fighter Fly
Fighter Fly
Posts: 40
Joined: Tue Nov 29, 2022 7:15 pm
Flair: oh worm?
Pronouns: they/it

Re: (Help) showing custom pictures with lua

Postby vee_Sleepy » Mon Dec 05, 2022 5:29 am

i might look into learning how to code custom bosses, in place of reskinning the pre-existing bunch
the most i'm good at so far is the old fashioned "tons of events" SMBX boss, where you have timers and all that rigidly structured to change what's going on and probably an NPC spawner or a shell or SMB3 ice block for you to damage the boss at all. and also, of course, when you can hit the boss, its just a reskinned Mother Brain lmao
but my original question was just about showing custom images under certain conditions, and this might be deviating too much from that


Return to “LunaLua Help”

Who is online

Users browsing this forum: No registered users and 0 guests

SMWCentralTalkhausMario Fan Games GalaxyKafukaMarioWikiSMBXEquipoEstelari