Related
I am trying to make a main menu with lua and love2d, this is my first time doing so and sadly there are no tutorials on the matter so I took a shot at it myself. I keep runing into this error and i dont know how to fix it, Please help!
Full error message: Error main.lua:23: attempt to index upvalue 'Menu' (a boolean value) Traceback main.lua:23: in function 'load' [C]: in function 'xpcall' [C]: in function 'xpcall'
Menu file
local Menu = {}
local game_state = 'menu'
local menus = { 'Play', 'Quit' }
local selected_menu_item = 1
local window_width
local window_height
local font_height
local Map = require("map")
-- functions
local draw_menu
local menu_keypressed
local draw_game
local game_keypressed
function Menu:load()
-- get the width and height of the game window in order to center menu items
self.window_width, self.window_height = love.graphics.getDimensions()
-- use a big font for the menu
self.font = love.graphics.newFont("assets/bit.ttf", 36)
-- get the height of the font to help calculate vertical positions of menu items
self.font_height = font:getHeight()
end
function Menu:update(dt)
end
function Menu:draw()
local horizontal_center = self.window_width / 2
local vertical_center = self.window_height / 2
local start_y = vertical_center - (self.font_height * (#menus / 2))
-- draw guides to help check if menu items are centered, can remove later
-- love.graphics.setColor(1, 1, 1, 0.1)
-- love.graphics.line(horizontal_center, 0, horizontal_center, window_height)
-- love.graphics.line(0, vertical_center, window_width, vertical_center)
-- draw game title
love.graphics.setColor(1, 1, 1, 1)
love.graphics.printf("Breakout", 0, 150, window_width, 'center')
-- draw menu items
for i = 1, #menus do
-- currently selected menu item is yellow
if i == selected_menu_item then
love.graphics.setColor(1, 1, 0, 1)
-- other menu items are white
else
love.graphics.setColor(1, 1, 1, 1)
end
-- draw this menu item centered
love.graphics.printf(menus[i], 0, start_y + self.font_height * (i-1), self.window_width, 'center')
end
end
function Menu:keypressed(key)
-- pressing Esc on the main menu quits the game
if key == 'escape' then
love.event.quit()
-- pressing up selects the previous menu item, wrapping to the bottom if necessary
elseif key == 'up' then
selected_menu_item = selected_menu_item - 1
if selected_menu_item < 1 then
selected_menu_item = #menus
end
-- pressing down selects the next menu item, wrapping to the top if necessary
elseif key == 'down' then
selected_menu_item = selected_menu_item + 1
if selected_menu_item > #menus then
selected_menu_item = 1
end
-- pressing enter changes the game state (or quits the game)
elseif key == 'return' or key == 'kpenter' then
if menus[selected_menu_item] == 'Play' then
Map:load()
elseif menus[selected_menu_item] == 'Quit' then
love.event.quit()
end
end
end
Main File
love.graphics.setDefaultFilter("nearest", "nearest")
local Player = require("player")
local Coin = require("coin")
local GUI = require("gui")
local Spike = require("spike")
local Camera = require("camera")
local Stone = require("stone")
local Enemy = require("enemy")
local Map = require("map")
local Enemy2 = require("enemy2")
local Sound = require("sound")
local Menu = require("menu")
function love.load()
Sound:init("music", "sfx/music.wav", "static")
Sound:init("breeze", "sfx/breeze.mp3", "static")
Enemy.loadAssets()
Enemy2.loadAssets()
Map:load()
background = love.graphics.newImage("assets/background2.png")
Player:load()
GUI:load()
Menu:load()
end
function love.update(dt)
Sound:update()
World:update(dt)
Player:update(dt)
Coin.updateAll(dt)
Stone.updateAll(dt)
Enemy.updateAll(dt)
Enemy2.updateAll(dt)
GUI:load(dt)
Spike:updateAll(dt)
Camera:setPosition(Player.x, 0)
Map:update(dt)
Menu:load()
end
function love.draw()
love.graphics.draw(background)
Map.level:draw(-Camera.x, -Camera.y, Camera.scale, Camera.scale)
Menu:draw()
Camera:apply()
Player:draw()
Enemy.drawAll()
Enemy2.drawAll()
Coin.drawAll()
Spike.drawAll()
Stone.drawAll()
Camera:clear()
GUI:draw()
end
function love.playmusic()
loopingMusic = Sound:play("music", "sfx", 0.05, 1)
loopingMusic:setLooping(true)
end
function love.playBreeze()
loopingBreeze = Sound:play("breeze", "sfx", 0.3, 1)
loopingBreeze:setLooping(true)
end
function love.keypressed(key)
Player:jump(key)
Menu:keypressed(key)
if key == "m" then
Sound:stop("sfx")
end
end
function beginContact(a, b, collision)
if Coin.beginContact(a, b, collision) then
return
end
if Spike.beginContact(a, b, collision) then
return end
Enemy.beginContact(a, b, collision)
Enemy2.beginContact(a, b, collision)
Player:beginContact(a, b, collision)
end
function endContact(a, b, collision)
Player:endContact(a, b, collision)
end
function endGame()
love.event.quit()
end
Your menu.lua does not return your table Menu.
So assiging menu = require("menu") result in menu referring to Menu but to true.
From the Lua manual:
Once a loader is found, require calls the loader with a single
argument, modname. If the loader returns any value, require assigns
the returned value to package.loaded[modname]. If the loader returns
no value and has not assigned any value to package.loaded[modname],
then require assigns true to this entry. In any case, require
returns the final value of package.loaded[modname].
So in line 23 of main.lua you're actually attempting to index true, a boolean value. Menu:load()
Add return Menu to the end of your menu.lua
new to Lua and love. I'm trying to animate a character for my platform game. I know my key binds and all work but I have never animated before, so I don't even know if I'm going in the right direction or not. I've tried looking up guides so I can compare my code to someone else's but it seems that most of them are outdated. Originally my player was just a white rectangle but now im trying to actually give it a sprite.
Here's my main.lua
local STI = require("sti")
local anim8 = require('anim8')
require("MC")
function love.load()
map1 = STI("map/map1.lua", {"box2d"})
Physics = love.physics.newWorld(0,0)
Physics:setCallbacks(beginContact, endContact)
map1:box2d_init(Physics)
map1.layers.Solid.visible = false
background = love.graphics.newImage("assets/Base pack/bg.png")
mc:load()
end
function love.update(dt)
Physics:update(dt)
mc:update(dt)
end
function love.draw()
love.graphics.push()
love.graphics.scale(5,3)
love.graphics.draw(background)
love.graphics.pop()
map1:draw(0, 0, 2, 2)
love.graphics.push()
love.graphics.scale(2,2)
mc:draw()
love.graphics.pop()
end
function love.keypressed(key)
mc:jump(key)
if keypressed == "escape" then
love.event.quit(0)
end
end
function beginContact(a, b, collision)
mc:beginContact(a, b, collision)
end
function endContact(a, b, collision)
mc:endContact(a, b, collision)
end
I don't believe that there is anything wrong with my main but i think it's necessary to recreate the problem (sorry if it makes this too long). Now my mc.lua is where I'm having the problem since im trying to animate the player themselves by giving them a jump idle and walk animation, I think i will give them a damaged and death animation later.
local anim8 = require('anim8')
mc = {}
spr_mc_walk = love.graphics.newImage("assets/mc sprites/1 Pink_Monster/Pink_Monster_Walk_6.png")
local w = anim8.newGrid(32, 32, spr_mc_walk:getWidth(), spr_mc_walk:getHeight())
walk = anim8.newAnimation(w('1-6', 1), 0.1)
spr_mc_idle = love.graphics.newImage("assets/mc sprites/1 Pink_Monster/Pink_Monster_Idle_4.png")
local i = anim8.newGrid(32, 32, spr_mc_idle:getWidth(), spr_mc_idle:getHeight())
idle = anim8.newAnimation(i('1-4', 1), 0.1)
spr_mc_jump = love.graphics.newImage("assets/mc sprites/1 Pink_Monster/Pink_Monster_Jump_8.png")
local j = anim8.newGrid(32, 32, spr_mc_jump:getWidth(), spr_mc_jump:getHeight())
jump = anim8.newAnimation(j('1-8', 1), 0.1)
obj_mc = walk
function mc:load()
self.x = 100
self.y = 0
self.width = 20
self.height = 60
self.xvel = 0
self.yvel = 0
self.maxspeed = 200
self.acceleration = 4000 -- max speed
self.friction = 3900 -- how long it takes them to reach max speed
self.gravity = 1000
self.jumpAmount = -500
self.grounded = false
self.physics = {}
self.physics.body = love.physics.newBody(Physics, self.x, self.y, "dynamic")
self.physics.body:setFixedRotation(true)
self.physics.shape = love.physics.newRectangleShape(self.width, self.height)
self.physics.fixture = love.physics.newFixture(self.physics.body, self.physics.shape)
end
function mc:draw()
love.graphics.draw(obj_mc, self.x, self.y)
end
This is most of my mc or player function, except for movement and such but this has all the code that I'm confused with. I'm pretty sure I wrote the code right I'm just confused on how to actually implement it now that I have it written down. I thought just doing the draw function would actually draw the idle version of the character but then there's where I get the error. If you need anymore code or anymore details just let me know.
The error that this is happening at is
Error
MC.lua:41: bad argument #1 to 'draw' (Drawable expected, got table)
Traceback
[C]: in function 'draw'
MC.lua:41: in function 'draw'
main.lua:30: in function 'draw'
[C]: in function 'xpcall'
I haven't done any of that for a while, but I believe obj_mc, in this case, is a table of the frames. You need to loop through them during update.
local anim8timer = 0
local anim8index = 1
local anim8rate = 0.2 -- pick an animation rate that looks good for your game
function mc:update( dt )
anim8timer = anim8timer +dt -- add delta time
if anim8timer >= anim8rate then
anim8timer = anim8timer -anim8rate -- reset timer
anim8index = anim8index +1 -- next frame
if anim8index > #obj_mc then anim8index = 1 end -- loop frames
end
end
function mc:draw()
love.graphics.draw( obj_mc[ anim8index ], self.x, self.y )
end
They may have a built-in function that accomplishes some of that, so look for anything that resembles this in the Love2D forum.
I need a script that can do an animation when you are standing on a brick. I just don't know how to do the animation. I can't find a free model with the animation I am looking for. Here is a preview of how I want the hands up. PREVIEW OF THE ANIMATION
The brick you are standing on is
script.Parent
There are two main ways of animation; The newer Animations and the older Joints.
The guide should be able to help you to getting started with animations. It even got a video.
If you want to use a old style Joint animation, something like this might work:
local Block = script.Parent
local function MakeFakeShoulder(Character, Side)
local Controller = { ["Stop"] = function() end }
local Torso = Character:findFirstChild("Torso")
local Arm = Character:findFirstChild(Side .. " Arm")
if not Torso or not Arm then return Controller end
local Shoulder = Torso:findFirstChild(Side .. " Shoulder")
if Shoulder then
local FakeShoulder = Instance.new("ManualWeld")
FakeShoulder.Name = "Fake " .. Side .. " Shoulder"
FakeShoulder.C0 = CFrame.new(1.5 * (Side == "Right" and 1 or -1),0.5,0)
FakeShoulder.C1 = CFrame.new(0,0.5,0) * CFrame.fromAxisAngle(Vector3.FromAxis(Enum.Axis.Z), math.rad(-180))
FakeShoulder.Part0 = Torso
FakeShoulder.Part1 = Arm
FakeShoulder.Parent = Torso
Shoulder.Parent = nil
function Controller:Stop()
Shoulder.Parent = Torso
FakeShoulder:Destroy()
end
end
return Controller
end
local function MakeFakeShoulders(Character)
local Controller = { }
local Right = MakeFakeShoulder(Character, "Right")
local Left = MakeFakeShoulder(Character, "Left")
function Controller:Stop()
Right:Stop()
Left:Stop()
end
return Controller
end
local function GetHumanoid(Part)
if Part.Parent == nil then return nil end
return Part.Parent:findFirstChild("Humanoid")
end
local CurrentlyTouching = { }
Block.Touched:connect(function(Part)
local Humanoid = GetHumanoid(Part)
if not Humanoid then return end
CurrentlyTouching[Humanoid] = CurrentlyTouching[Humanoid] or 0
CurrentlyTouching[Humanoid] = CurrentlyTouching[Humanoid] + 1
if CurrentlyTouching[Humanoid] > 1 then return end
local Controller = MakeFakeShoulders(Part.Parent)
while CurrentlyTouching[Humanoid] > 0 do
if GetHumanoid(Block.TouchEnded:wait()) == Humanoid then
CurrentlyTouching[Humanoid] = CurrentlyTouching[Humanoid] - 1
end
end
Controller:Stop()
end)
Note that if the ending touch do not register good enough, make a invisible CanCollide = false bounding part that is bigger than the visual part and put the script in that one instead,
I am trying to use this in a project, but I cannot figure out how to place a touch event listener to each of the icons/objects in the carousel, If someone could provide a quick answer of how to do that I'd appreciate it.
local NUM_ITEMS=20;
local radiusX= 200;
local radiusY= 40;
local centerX = 240;
local centerY = 160;
local speed = 0.05;
local perspective = 3;
local carousel = display.newGroup()
local icons = {}
local function zSort(myTable, myGroup)
table.sort(myTable,
function(a, b)
return a.depth < b.depth -- depth is your custom field
end
)
for i = 1, #myTable do
myGroup:insert(myTable[i].img)
end
end
function Icon(i)
local this = {}
local icon = display.newImage(carousel, "images/icon"..i..".png")
this.angle = (i-1) * math.rad(360/NUM_ITEMS);
this.img = icon
return this
end
function update(event)
local icon
local sin = math.sin
local cos = math.cos
for i=1, NUM_ITEMS, 1 do
icon = icons[i]
local img = icon.img
img.x = cos(icon.angle) * radiusX + centerX
img.y = sin(icon.angle) * radiusY + centerY
local s = (img.y - perspective) / (centerX + radiusY - perspective)
img.xScale = s*0.25
img.yScale = s*0.25
icon.angle = (icon.angle + speed) --%math.rad(360)
icon.depth = s
end
zSort(icons, carousel)
end
for i=1, NUM_ITEMS, 1 do
local icon = Icon(i)
icons[i] = icon
end
function onTouch(event)
if(event.phase=="moved") then
speed = (event.x - centerX) / 2000;
end
end
Runtime:addEventListener("enterFrame",update)
Runtime:addEventListener("touch", onTouch)
I can't exactly understood what you really need. But if you want to add individual touch to all same icons in a localGroup, then you can add the icons as an icon array and give specific tag to each and can give individual touch, as follows:
local icons = {}
for i=1,10 do
icons[i] = display.newImage(i..".png")
icons[i].tag = i
end
local function touchIt(e)
print(e.target.tag)
--[[ icons[e.target.tag] can be used to identify
and set properties to the touched icon --]]
end
for i=1,10 do
icons[i]:addEventListener("touch",touchIt)
end
OR
if you want to identify all group elements as the same and give touch, then you can use same tag/ give userdata to all icons and can give same touch action to all group elements(as follows).
local icons = {}
for i=1,10 do
icons[i] = display.newImage(i..".png")
icons[i].tag = 1 --[[ you can also use icons[i].userdata = "icons"
(or any string)--]]
end
local function touchIt(e)
print(e.target.tag) -- It willo be 1 for all icons
--[[ icons[e.target.tag] can be used to identify
whether if it is under 'icons' --]]
--[[ or use userdata as follows --]]
print(e.target.userdata)--[[ out put is a string
identifying the group/element--]]
end
for i=1,10 do
icons[i]:addEventListener("touch",touchIt)
end
I would like to create an animation which enables the user to go backward and forward through the steps of simulation.
An animation has to simulate the iterative process of channel decoding (a receiver receives a block of bits, performs an operation and then checks if the block corresponds to parity rules. If the block doesn't correspond the operation is performed again and the process finally ends when the code corresponds to a given rules).
I have written the functions which perform the decoding process and return a m x n x i matrix where m x n is the block of data and i is the iteration index. So if it takes 3 iterations to decode the data the function returns a m x n x 3 matrix with each step is stired.
In the GUI (.fig file) I put a "decode" button which runs the method for decoding and there are buttons "back" and "forward" which have to enable the user to switch between the data of recorded steps.
I have stored the "decodedData" matrix and currentStep value as a global variable so by clicking "forward" and "next" buttons the indices have to change and point to appropriate step states.
When I tried to debug the application the method returned the decoded data but when I tried to click "back" and "next" the decoded data appeared not to be declared.
Does anyone know how is it possible to access (or store) the results of the functions in order to enable the described logic which I want to implement in Matlab GUI?
Ultimately, this is a scoping of variables problem.
Global variables is rarely the right answer.
This video discusses the handles structure in GUIDE:
http://blogs.mathworks.com/videos/2008/04/17/advanced-matlab-handles-and-other-inputs-to-guide-callbacks/
This video discusses sharing of variables between GUIs and could apply to a single GUI problem also.
http://blogs.mathworks.com/videos/2005/10/03/guide-video-part-two/
The trick is to use nested functions so that they share the same workspace. Since I already started with an example in your last question, now I'm simply adding GUI controls to enable going forward/backward interactively, in addition to play/stop the animation:
function testAnimationGUI()
%# coordinates
t = (0:.01:2*pi)'; %# 'fix SO syntax highlight
D = [cos(t) -sin(t)];
%# setup a figure and axis
hFig = figure('Backingstore','off', 'DoubleBuffer','on');
hAx = axes('Parent',hFig, 'XLim',[-1 1], 'YLim',[-1 1], ...
'Drawmode','fast', 'NextPlot','add');
axis(hAx, 'off','square')
%# draw circular path
line(D(:,1), D(:,2), 'Color',[.3 .3 .3], 'LineWidth',1);
%# initialize point
hLine = line('XData',D(1,1), 'YData',D(1,2), 'EraseMode','xor', ...
'Color','r', 'marker','.', 'MarkerSize',50);
%# init text
hTxt = text(0, 0, num2str(t(1)), 'FontSize',12, 'EraseMode','xor');
i=0;
animation = false;
hBeginButton = uicontrol('Parent',hFig, 'Position',[1 1 30 20], ...
'String','<<', 'Callback',#beginButton_callback);
hPrevButton = uicontrol('Parent',hFig, 'Position',[30 1 30 20], ...
'String','<', 'Callback',#previousButton_callback);
hNextButton = uicontrol('Parent',hFig, 'Position',[60 1 30 20], ...
'String','>', 'Callback',#nextButton_callback);
hEndButton = uicontrol('Parent',hFig, 'Position',[90 1 30 20], ...
'String','>>', 'Callback',#endButton_callback);
hSlider = uicontrol('Parent',hFig, 'Style','slider', 'Value',1, 'Min',1,...
'Max',numel(t), 'SliderStep', [10 100]./numel(t), ...
'Position',[150 1 300 20], 'Callback',#slider_callback);
hPlayButton = uicontrol('Parent',hFig, 'Position',[500 1 30 20], ...
'String','|>', 'Callback',#playButton_callback);
hStopButton = uicontrol('Parent',hFig, 'Position',[530 1 30 20], ...
'String','#', 'Callback',#stopButton_callback);
%#----------- NESTED CALLBACK FUNCTIONS -----------------
function beginButton_callback(hObj,eventdata)
updateCircle(1)
end
function endButton_callback(hObj,eventdata)
updateCircle(numel(t))
end
function nextButton_callback(hObj,eventdata)
i = i+1;
if ( i > numel(t) ), i = 1; end
updateCircle(i)
end
function previousButton_callback(hObj,eventdata)
i = i-1;
if ( i < 1 ), i = numel(t); end
updateCircle(i)
end
function slider_callback(hObj, eventdata)
i = round( get(gcbo,'Value') );
updateCircle(i)
end
function playButton_callback(hObj, eventdata)
animation = true;
while animation
i = i+1;
if ( i > numel(t) ), i = 1; end
updateCircle(i)
end
end
function stopButton_callback(hObj, eventdata)
animation = false;
end
function updateCircle(idx)
set(hSlider, 'Value', rem(idx-1,numel(t))+1) %# update slider to match
set(hLine,'XData',D(idx,1), 'YData',D(idx,2)) %# update X/Y data
set(hTxt,'String',num2str(t(idx))) %# update angle text
drawnow %# force refresh
if ~ishandle(hAx), return; end %# check valid handle
end
%#-------------------------------------------------------
end
You might find the slider functionality a bit buggy, but you get the idea :)